HTTP service for LFX API consumers to perform access-controlled queries for LFX resources, including typeahead and full-text search.
The implementation follows the clean architecture principles where:
- Domain Layer: Contains business logic and interfaces
- Service Layer: Orchestrates business operations
- Infrastructure Layer: Implements external dependencies
- Presentation Layer: Handles HTTP/API concerns (generated by Goa)
├── .github/ # Github files
│ └── workflows/ # Github Action workflow files
├── charts/ # Helm charts
├── design/ # GOA design specification files
├── gen/ # GOA generated code (HTTP server, client, OpenAPI)
├── cmd/ # Services (main packages)
│ └── query_svc/ # Query service implementation
├── internal/ # Internal service packages
│ ├── domain/ # Domain logic layer
│ │ ├── model/ # Domain models and entities
│ │ └── port/ # Domain interfaces/ports
│ ├── usecase/ # Business logic/use cases layer
│ ├── infrastructure/ # Infrastructure layer
│ └── middleware/ # HTTP middleware components
└── pkg/ # Shared packages for internal and external services
- ResourceService: Contains business logic and validation
- Domain Models: Core business entities and data structures
- Value Objects: Immutable objects that represent domain concepts
- ResourceSearcher Interface: Defines the contract for resource search operations
- AccessControlChecker Interface: Defines the contract for access control operations
- Business Logic: Application-specific business rules and operations
- Use Case Orchestration: Coordinates between domain models and infrastructure
The OpenSearch implementation includes query templates, a searcher, and a client for interacting with the OpenSearch cluster.
The NATS implementation consists of a client, access control logic, and request/response models for messaging and access control.
Dependency injection is performed in cmd/main.go
, where the concrete implementations for resource search and access control are selected based on configuration and then injected into the service constructor.
- Testability: Easy to swap implementations for testing
- Flexibility: Can easily switch between different search backends and access control systems
- Maintainability: Clear separation of concerns
- Scalability: Easy to add new search and access control implementations
- Independence: Layers don't depend on external frameworks
make docker-build
make docker-run
# Using mock implementations
SEARCH_SOURCE=mock ACCESS_CONTROL_SOURCE=mock go run cmd/main.go
# With custom port
SEARCH_SOURCE=mock ACCESS_CONTROL_SOURCE=mock go run cmd/main.go -p 3000
# Using OpenSearch and NATS (production-like setup)
SEARCH_SOURCE=opensearch \
ACCESS_CONTROL_SOURCE=nats \
OPENSEARCH_URL={{placeholder}} \
OPENSEARCH_INDEX=resources \
NATS_URL{{placeholder}} \
go run cmd/main.go
Search Implementation:
SEARCH_SOURCE
: Choose between "mock" or "opensearch" (default: "opensearch")
OpenSearch Configuration:
OPENSEARCH_URL
: OpenSearch URL (default:http://localhost:9200
)OPENSEARCH_INDEX
: OpenSearch index name (default: "resources")
Access Control Implementation:
ACCESS_CONTROL_SOURCE
: Choose between "mock" or "nats" (default: "nats")
NATS Configuration:
NATS_URL
: NATS server URL (default:nats://localhost:4222
)NATS_TIMEOUT
: Request timeout duration (default: "10s")NATS_MAX_RECONNECT
: Maximum reconnection attempts (default: "3")NATS_RECONNECT_WAIT
: Time between reconnection attempts (default: "2s")
Server Configuration:
-p
: HTTP port (default: "8080")-bind
: Interface to bind on (default: "*")-d
: Enable debug logging
The service exposes a RESTful API through the Goa framework:
GET /query/resources?name=committee&type=committee&v=1
Parameters:
name
: Resource name or alias (supports typeahead search)type
: Resource type to filter byparent
: Parent resource for hierarchical queriestags
: Array of tags to filter bysort
: Sort order (name_asc, name_desc, updated_asc, updated_desc)page_token
: Pagination tokenv
: API version (required)
Response:
{
"resources": [
{
"type": "committee",
"id": "123",
"data": {
"name": "Technical Advisory Committee",
"description": "Main technical governance body",
"status": "active"
}
}
],
"page_token": "offset_50",
"cache_control": "public, max-age=300"
}
The clean architecture makes testing straightforward:
// Use mock implementations for unit tests
searcher := mock.NewMockResourceSearcher()
searcher.AddResource(testResource)
accessChecker := mock.NewMockAccessControlChecker()
accessChecker.SetAccessResult(testResult)
service := service.NewResourceService(searcher, accessChecker)
result, err := service.QueryResources(ctx, criteria)
To add a new search implementation:
- Create a new package in
internal/infrastructure/
- Implement the
domain.ResourceSearcher
interface - Add configuration options to
main.go
- Update the dependency injection switch statement
To add a new access control implementation:
- Create a new package in
internal/infrastructure/
- Implement the
domain.AccessControlChecker
interface - Add configuration options to
main.go
- Update the dependency injection switch statement
This project uses the GOA Framework for API generation. You'll need to install GOA before building the project.
Follow the GOA installation guide to install GOA:
go install goa.design/goa/v3/cmd/goa@latest
Verify the installation:
goa version
The project uses GOA to generate API code from the design specification. Run the following command to generate all necessary code:
goa gen github.com/linuxfoundation/lfx-v2-query-service/design
This command generates:
- HTTP server and client code
- OpenAPI specification
- Service interfaces and types
- Transport layer implementations
Note: The initial cmd
structure was generated using GOA's example generator:
goa example github.com/linuxfoundation/lfx-v2-query-service/design
This command generated the basic server structure, which was then customized and adjusted to fit our project's clean architecture principles.
-
Make design changes: Edit files in the
design/
directory -
Regenerate code: Run
goa gen github.com/linuxfoundation/lfx-v2-query-service/design
after design changes -
Build the project:
go build cmd
-
Run with mock data (for development):
SEARCH_SOURCE=mock ACCESS_CONTROL_SOURCE=mock go run ./cmd
-
Run tests:
make test # or run go test to set custom flags go test ./... -v
-
Lint the code
# From the root of the directory, run megalinter (https://megalinter.io/latest/mega-linter-runner/) to ensure the code passes the linter checks. The CI/CD has a check that uses megalinter. npx mega-linter-runner .
-
Docker build + K8
# Build the dockerfile (from the root of the repo) docker build -t lfx-v2-query-service:<release_number> . # Install the helm chart for the service into the lfx namespace (from the root of the repo) helm install lfx-v2-query-service ./charts/lfx-v2-query-service/ -n lfx # Once you have already installed the helm chart and need to just update it, use the following command (from the root of the repo): helm upgrade lfx-v2-query-service ./charts/lfx-v2-query-service/ -n lfx
To contribute to this repository:
- Fork the repository
- Make your changes
- Submit a pull request
Copyright The Linux Foundation and each contributor to LFX.
This project’s source code is licensed under the MIT License. A copy of the
license is available in LICENSE
.
This project’s documentation is licensed under the Creative Commons Attribution
4.0 International License (CC-BY-4.0). A copy of the license is available in
LICENSE-docs
.