Skip to main content

Query API

Introduction

In the Codebricks framework, Query APIs serve as the entry points for retrieving data from the backend. Unlike Command APIs that handle state-changing operations, Query APIs are designed for fetching information based on query parameters. They are implemented as GET requests.

These APIs convert incoming request parameters into Query objects, which are then processed by QueryHandlers. The results are returned to the client as API responses.

Implementation

We split the API into two parts:

  1. Infrastructure Agnostic API File: This handles the core API logic.
  2. Handler File: This translates AWS-specific events into technology-agnostic requests.

API

The API implementation is found at: Task/src/useCases/read/ActiveTaskOverview/infrastructure/ActiveTaskOverviewApi.ts.

import { ValidationError, NotFoundError, OverwriteProtectionBody } from "@codebricks/codebricks-framework";
import { GetAllQuery } from "../application/GetAllQuery";
import { GetAllQueryHandler } from "../application/GetAllQueryHandler";
import { ActiveTaskOverviewEntity } from "shared/application/readmodels/ActiveTaskOverviewEntity";

export interface ActiveTaskOverviewApiRequest {
}

export interface ActiveTaskOverviewApiResponse {
statusCode: number;
body: string;
headers: any;
}

export class ActiveTaskOverviewApi {
constructor(readonly queryHandler: GetAllQueryHandler = new GetAllQueryHandler()) {
}

@OverwriteProtectionBody(false)
async handle(request: ActiveTaskOverviewApiRequest): Promise<ActiveTaskOverviewApiResponse> {
const headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true
};
try {
const query: GetAllQuery = new GetAllQuery({
});
const result: ActiveTaskOverviewEntity[] = await this.queryHandler.handle(query);

return {
statusCode: 200,
body: JSON.stringify({ data: result }),
headers: headers
};
} catch (error) {
console.log(error);
if (error instanceof ValidationError) {
return {
statusCode: 400,
body: JSON.stringify({ error: error.message }),
headers: headers
};
} else if (error instanceof SyntaxError && error.message.match(/Unexpected.token.*JSON.*/i)) {
return {
statusCode: 400,
body: '{ "error": "bad request: invalid json"}',
headers: headers
};
}

return {
statusCode: 500,
body: '{ "error": "Internal Server Error"}',
headers: headers
};
}
}
}

The ActiveTaskOverviewApi class provides methods for:

  • Converting API requests into Query objects.
  • Passing these queries to the QueryHandler.
  • Building responses from the results returned by the QueryHandler.
  • Handling and rendering errors appropriately.

API Handler

The API Handler is located at: Task/src/useCases/read/ActiveTaskOverview/infrastructure/ActiveTaskOverviewApiHandler.ts.

import { APIGatewayProxyEvent, APIGatewayProxyResult } from "@codebricks/codebricks-framework";
import { ActiveTaskOverviewApi } from "./ActiveTaskOverviewApi";
import { ActiveTaskOverviewApiRequest } from "./ActiveTaskOverviewApi";
import { initDataSource } from "shared/infrastructure/persistence/AppDataSource";

export async function handler(event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> {
try {
await initDataSource();
const activeTaskOverviewApi: ActiveTaskOverviewApi = new ActiveTaskOverviewApi();
const request: ActiveTaskOverviewApiRequest = {
};
return await activeTaskOverviewApi.handle(request) as unknown as Promise<APIGatewayProxyResult>;
} catch (error: any) {
console.log(error);
if (error instanceof SyntaxError && error.message.match(/Unexpected.token.*JSON.*/i)) {
return Promise.resolve({
statusCode: 400,
body: '{ "error": "bad request: invalid json"}',
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true
}
}) as Promise<APIGatewayProxyResult>;
} else{
return Promise.resolve({
statusCode: 500,
body: '{ "error": "Internal Server Error"}',
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true
}
}) as Promise<APIGatewayProxyResult>;
}
}
}

The ActiveTaskOverviewApiHandler function serves as the Lambda entry point, translating AWS API Gateway events into requests handled by the ActiveTaskOverviewApi. It is responsible for:

  • Initializing the data source.
  • Creating an instance of ActiveTaskOverviewApi.
  • Mapping API Gateway events to API requests.
  • Returning the appropriate responses based on the results or errors.

Best Practices

  • Separation of Concerns: Keep API and API Handler code separate to maintain clarity and manageability.
  • Error Management: Implement detailed error handling to ensure clear and actionable error responses.
  • Performance: Optimize query handling and response generation for efficient processing.