Skip to content

Commit

Permalink
IMN-742 - API Gateway - GET Agreements (#903)
Browse files Browse the repository at this point in the history
  • Loading branch information
ecamellini authored Sep 11, 2024
1 parent 6c3bd7c commit 45d8991
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 5 deletions.
11 changes: 11 additions & 0 deletions packages/api-clients/src/agreementApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as agreementApi from "./generated/agreementApi.js";
import { QueryParametersByAlias } from "./utils.js";

type Api = typeof agreementApi.agreementApi.api;

export type GetAgreementsQueryParams = QueryParametersByAlias<
Api,
"getAgreements"
>;

export * from "./generated/agreementApi.js";
10 changes: 10 additions & 0 deletions packages/api-clients/src/apiGatewayApi.ts
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
import * as apiGatewayApi from "./generated/apiGatewayApi.js";
import { QueryParametersByAlias } from "./utils.js";

type Api = typeof apiGatewayApi.gatewayApi.api;

export type GetAgreementsQueryParams = QueryParametersByAlias<
Api,
"getAgreements"
>;

export * from "./generated/apiGatewayApi.js";
2 changes: 1 addition & 1 deletion packages/api-clients/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * as agreementApi from "./generated/agreementApi.js";
export * as agreementApi from "./agreementApi.js";
export * as attributeRegistryApi from "./attributeRegistryApi.js";
export * as authorizationApi from "./generated/authorizationApi.js";
export * as authorizationManagementApi from "./generated/authorizationManagementApi.js";
Expand Down
24 changes: 24 additions & 0 deletions packages/api-gateway/src/api/agreementApiConverter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { agreementApi, apiGatewayApi } from "pagopa-interop-api-clients";
import { assertAgreementStateNotDraft } from "../services/validators.js";

const allowedAgreementStates: apiGatewayApi.AgreementState[] = [
apiGatewayApi.AgreementState.Values.PENDING,
apiGatewayApi.AgreementState.Values.ACTIVE,
apiGatewayApi.AgreementState.Values.SUSPENDED,
apiGatewayApi.AgreementState.Values.ARCHIVED,
apiGatewayApi.AgreementState.Values.MISSING_CERTIFIED_ATTRIBUTES,
];

export function toApiGatewayAgreementIfNotDraft(
agreement: agreementApi.Agreement
): apiGatewayApi.Agreement {
Expand All @@ -15,3 +23,19 @@ export function toApiGatewayAgreementIfNotDraft(
state: agreement.state,
};
}

export function toAgreementProcessGetAgreementsQueryParams(
queryParams: apiGatewayApi.GetAgreementsQueryParams
): Omit<agreementApi.GetAgreementsQueryParams, "offset" | "limit"> {
const { producerId, consumerId, eserviceId, descriptorId, states } =
queryParams;

return {
producersIds: producerId ? [producerId] : [],
consumersIds: consumerId ? [consumerId] : [],
eservicesIds: eserviceId ? [eserviceId] : [],
descriptorsIds: descriptorId ? [descriptorId] : [],
showOnlyUpgradeable: false,
states: states && states.length > 0 ? states : allowedAgreementStates,
};
}
9 changes: 9 additions & 0 deletions packages/api-gateway/src/models/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ApiError, makeApiProblemBuilder } from "pagopa-interop-models";

export const errorCodes = {
invalidAgreementState: "0001",
producerAndConsumerParamMissing: "0002",
};

export type ErrorCodes = keyof typeof errorCodes;
Expand All @@ -19,3 +20,11 @@ export function invalidAgreementState(
title: "Invalid agreement state",
});
}

export function producerAndConsumerParamMissing(): ApiError<ErrorCodes> {
return new ApiError({
detail: "Either producerId or consumerId required",
code: "producerAndConsumerParamMissing",
title: "Producer and Consumer param missing",
});
}
25 changes: 23 additions & 2 deletions packages/api-gateway/src/routers/apiGatewayRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import { fromApiGatewayAppContext } from "../utilities/context.js";
import { agreementServiceBuilder } from "../services/agreementService.js";
import { PagoPAInteropBeClients } from "../clients/clientsProvider.js";
import { makeApiProblem } from "../models/errors.js";
import { getAgreementErrorMapper } from "../utilities/errorMappers.js";
import {
getAgreementErrorMapper,
getAgreementsErrorMapper,
} from "../utilities/errorMappers.js";

const apiGatewayRouter = (
ctx: ZodiosContext,
Expand All @@ -29,7 +32,25 @@ const apiGatewayRouter = (
.get(
"/agreements",
authorizationMiddleware([M2M_ROLE]),
async (_req, res) => res.status(501).send()
async (req, res) => {
const ctx = fromApiGatewayAppContext(req.ctx, req.headers);

try {
const agreements = await agreementService.getAgreements(
ctx,
req.query
);

return res.status(200).json(agreements).send();
} catch (error) {
const errorRes = makeApiProblem(
error,
getAgreementsErrorMapper,
ctx.logger
);
return res.status(errorRes.status).json(errorRes).end();
}
}
)
.get(
"/agreements/:agreementId",
Expand Down
36 changes: 35 additions & 1 deletion packages/api-gateway/src/services/agreementService.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,48 @@
import { agreementApi, apiGatewayApi } from "pagopa-interop-api-clients";
import { WithLogger } from "pagopa-interop-commons";
import { getAllFromPaginated, WithLogger } from "pagopa-interop-commons";
import { AgreementProcessClient } from "../clients/clientsProvider.js";
import { ApiGatewayAppContext } from "../utilities/context.js";
import { toApiGatewayAgreementIfNotDraft } from "../api/agreementApiConverter.js";
import { producerAndConsumerParamMissing } from "../models/errors.js";
import { toAgreementProcessGetAgreementsQueryParams } from "../api/agreementApiConverter.js";

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function agreementServiceBuilder(
agreementProcessClient: AgreementProcessClient
) {
return {
getAgreements: async (
{ logger, headers }: WithLogger<ApiGatewayAppContext>,
queryParams: apiGatewayApi.GetAgreementsQueryParams
): Promise<apiGatewayApi.Agreements> => {
const { producerId, consumerId, eserviceId, descriptorId, states } =
queryParams;

logger.info(
`Retrieving agreements for producerId ${producerId} consumerId ${consumerId} eServiceId ${eserviceId} descriptorId ${descriptorId} states ${states}`
);

if (producerId === undefined && consumerId === undefined) {
throw producerAndConsumerParamMissing();
}

const getAgreementsQueryParams =
toAgreementProcessGetAgreementsQueryParams(queryParams);

const agreements = await getAllFromPaginated<agreementApi.Agreement>(
async (offset, limit) =>
await agreementProcessClient.getAgreements({
headers,
queries: {
...getAgreementsQueryParams,
offset,
limit,
},
})
);
return { agreements: agreements.map(toApiGatewayAgreementIfNotDraft) };
},

getAgreementById: async (
{ logger, headers }: WithLogger<ApiGatewayAppContext>,
agreementId: agreementApi.Agreement["id"]
Expand Down
11 changes: 10 additions & 1 deletion packages/api-gateway/src/utilities/errorMappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ import { ErrorCodes as APIGatewayErrorCodes } from "../models/errors.js";

type ErrorCodes = APIGatewayErrorCodes | CommonErrorCodes;

const { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_INTERNAL_SERVER_ERROR } = constants;
const {
HTTP_STATUS_BAD_REQUEST,
HTTP_STATUS_NOT_FOUND,
HTTP_STATUS_INTERNAL_SERVER_ERROR,
} = constants;

export const getAgreementErrorMapper = (error: ApiError<ErrorCodes>): number =>
match(error.code)
.with("invalidAgreementState", () => HTTP_STATUS_NOT_FOUND)
.otherwise(() => HTTP_STATUS_INTERNAL_SERVER_ERROR);

export const getAgreementsErrorMapper = (error: ApiError<ErrorCodes>): number =>
match(error.code)
.with("producerAndConsumerParamMissing", () => HTTP_STATUS_BAD_REQUEST)
.otherwise(() => HTTP_STATUS_INTERNAL_SERVER_ERROR);

export const emptyErrorMapper = (): number => HTTP_STATUS_INTERNAL_SERVER_ERROR;

0 comments on commit 45d8991

Please sign in to comment.