Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#174877080] Upgrade to italia-utils 5.x #711

Merged
merged 13 commits into from
Oct 27, 2020
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@
"test:coverage": "dotenv -e .env.example -- jest -i --coverage",
"start": "node src/server.js",
"generate:proxy-models": "npm-run-all generate:proxy:* generate:api:* generate:messages:*",
"generate:proxy:api-models": "rimraf generated/backend && shx mkdir -p generated/backend && gen-api-models --api-spec api_backend.yaml --out-dir generated/backend",
"generate:proxy:notification-models": "rimraf generated/notifications && shx mkdir -p generated/notifications && gen-api-models --api-spec api_notifications.yaml --out-dir generated/notifications",
"generate:messages:notifications": "rimraf generated/messages && shx mkdir -p generated/messages && gen-api-models --api-spec notification_queue_messages.yaml --out-dir generated/messages",
"generate:proxy:pagopa-models": "rimraf generated/pagopa && shx mkdir -p generated/pagopa && gen-api-models --api-spec api_pagopa.yaml --out-dir generated/pagopa",
"generate:proxy:myportal-models": "rimraf generated/myportal && shx mkdir -p generated/myportal && gen-api-models --api-spec api_myportal.yaml --out-dir generated/myportal",
"generate:proxy:bpd-models": "rimraf generated/bpd && shx mkdir -p generated/bpd && gen-api-models --api-spec api_bpd.yaml --out-dir generated/bpd",
"generate:proxy:public-models": "rimraf generated/public && shx mkdir -p generated/public && gen-api-models --api-spec api_public.yaml --out-dir generated/public",
"generate:api:io": "rimraf generated/io-api && shx mkdir -p generated/io-api && gen-api-models --api-spec https://raw.githubusercontent.com/pagopa/io-functions-app/master/openapi/index.yaml --no-strict --out-dir generated/io-api --request-types --response-decoders",
"generate:proxy:bonus-models": "rimraf generated/bonus && shx mkdir -p generated/bonus && gen-api-models --api-spec api_bonus.yaml --out-dir generated/bonus",
"generate:api:io-bonus": "rimraf generated/io-bonus-api && shx mkdir -p generated/io-bonus-api && gen-api-models --api-spec https://raw.githubusercontent.com/pagopa/io-functions-bonus/master/openapi/index.yaml --no-strict --out-dir generated/io-bonus-api --request-types --response-decoders",
"generate:api:pagopaproxy": "rimraf generated/pagopa-proxy && shx mkdir -p generated/pagopa-proxy && gen-api-models --api-spec https://raw.githubusercontent.com/pagopa/io-pagopa-proxy/v0.8.6/api_pagopa.yaml --no-strict --out-dir generated/pagopa-proxy --request-types --response-decoders",
"generate:proxy:api-models": "rimraf generated/backend && gen-api-models --api-spec api_backend.yaml --out-dir generated/backend",
"generate:proxy:notification-models": "rimraf generated/notifications && gen-api-models --api-spec api_notifications.yaml --out-dir generated/notifications",
"generate:messages:notifications": "rimraf generated/messages && gen-api-models --api-spec notification_queue_messages.yaml --out-dir generated/messages",
"generate:proxy:pagopa-models": "rimraf generated/pagopa && gen-api-models --api-spec api_pagopa.yaml --out-dir generated/pagopa",
"generate:proxy:myportal-models": "rimraf generated/myportal && gen-api-models --api-spec api_myportal.yaml --out-dir generated/myportal",
"generate:proxy:bpd-models": "rimraf generated/bpd && gen-api-models --api-spec api_bpd.yaml --out-dir generated/bpd",
"generate:proxy:public-models": "rimraf generated/public && gen-api-models --api-spec api_public.yaml --out-dir generated/public",
"generate:api:io": "rimraf generated/io-api && gen-api-models --api-spec https://raw.githubusercontent.com/pagopa/io-functions-app/master/openapi/index.yaml --no-strict --out-dir generated/io-api --request-types --response-decoders --client",
"generate:proxy:bonus-models": "rimraf generated/bonus && gen-api-models --api-spec api_bonus.yaml --out-dir generated/bonus",
"generate:api:io-bonus": "rimraf generated/io-bonus-api && gen-api-models --api-spec https://raw.githubusercontent.com/pagopa/io-functions-bonus/master/openapi/index.yaml --no-strict --out-dir generated/io-bonus-api --request-types --response-decoders",
"generate:api:pagopaproxy": "rimraf generated/pagopa-proxy && gen-api-models --api-spec https://raw.githubusercontent.com/pagopa/io-pagopa-proxy/v0.8.6/api_pagopa.yaml --no-strict --out-dir generated/pagopa-proxy --request-types --response-decoders",
"generate:test-certs": "./scripts/generate-test-certs.sh certs",
"postversion": "git push && git push --tags",
"dist:modules": "modclean -r -n default:safe && yarn install --production",
Expand Down Expand Up @@ -118,7 +118,7 @@
"danger-plugin-digitalcitizenship": "^0.3.1",
"dotenv-cli": "^3.1.0",
"italia-tslint-rules": "^1.1.3",
"italia-utils": "^4.2.0",
"italia-utils": "^5.1.0",
"jest": "^23.6.0",
"lolex": "4.2.0",
"mock-redis-client": "^0.91.13",
Expand Down
232 changes: 13 additions & 219 deletions src/clients/api.ts
Original file line number Diff line number Diff line change
@@ -1,239 +1,33 @@
import {
ApiHeaderJson,
composeHeaderProducers,
composeResponseDecoders,
constantResponseDecoder,
createFetchRequestForApi,
ioResponseDecoder,
ReplaceRequestParams,
RequestHeaderProducer,
RequestParams,
TypeofApiCall
} from "italia-ts-commons/lib/requests";
import { ProblemJson } from "italia-ts-commons/lib/responses";
import { Omit } from "italia-ts-commons/lib/types";
import nodeFetch from "node-fetch";

import {
createProfileDefaultDecoder,
CreateProfileT,
getMessageDefaultDecoder,
getMessagesByUserDefaultDecoder,
GetMessagesByUserT,
GetMessageT,
getProfileDefaultDecoder,
GetProfileT,
getServiceDefaultDecoder,
GetServiceT,
getUserDataProcessingDefaultDecoder,
GetUserDataProcessingT,
getVisibleServicesDefaultDecoder,
GetVisibleServicesT,
StartEmailValidationProcessT,
updateProfileDefaultDecoder,
UpdateProfileT,
upsertUserDataProcessingDefaultDecoder,
UpsertUserDataProcessingT
} from "../../generated/io-api/requestTypes";
import { Client, createClient } from "../../generated/io-api/client";

// we want to authenticate against the platform APIs with the APIM header key or
// the Azure Functions header key, so we send both headers
function SubscriptionKeyHeaderProducer<P>(
/* function SubscriptionKeyHeaderProducer<P>(
token: string
): RequestHeaderProducer<P, "X-Functions-Key" | "Ocp-Apim-Subscription-Key"> {
return () => ({
"Ocp-Apim-Subscription-Key": token,
"X-Functions-Key": token
});
}
} */
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gunzip @francescopersico please take a look here:
the former code used to pass token to both X-Functions-Key andOcp-Apim-Subscription-Key header. With the latest implementation, only the latter is valued. Which is the correct configuration?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we must update the specs on io-functions-app to take only X-Functions-Key

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


export function APIClient(
baseUrl: string,
token: string,
// tslint:disable-next-line:no-any
fetchApi: typeof fetch = (nodeFetch as any) as typeof fetch // TODO: customize fetch with timeout
): {
readonly updateProfile: TypeofApiCall<typeof updateProfileT>;
readonly getMessage: TypeofApiCall<typeof getMessageT>;
readonly getMessages: TypeofApiCall<typeof getMessagesT>;
readonly getProfile: TypeofApiCall<typeof getProfileT>;
readonly createProfile: TypeofApiCall<typeof createProfileT>;
readonly upsertUserDataProcessing: TypeofApiCall<
typeof upsertUserDataProcessingT
>;
readonly emailValidationProcess: TypeofApiCall<
typeof emailValidationProcessT
>;
readonly getService: TypeofApiCall<typeof getServiceT>;
readonly getVisibleServices: TypeofApiCall<typeof getVisibleServicesT>;
readonly getUserDataProcessing: TypeofApiCall<typeof getUserDataProcessingT>;
} {
const options = {
): Client<"SubscriptionKey"> {
return createClient<"SubscriptionKey">({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this must be x-functions-key (Ocp-Apim-Subscription-Key is unused)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually is. The referenced api spec is

  SubscriptionKey:
    type: apiKey
    name: X-Functions-Key
    in: header

Under the hood, the generated client does the following:

headers: ({ SubscriptionKey }: { SubscriptionKey: string }) => ({
      "X-Functions-Key": `Bearer ${SubscriptionKey}`
    }),

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's right, not easy to grasp from the code here :-) (maybe we could add a comment?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done here

basePath: "",
baseUrl,
fetchApi
};

const tokenHeaderProducer = SubscriptionKeyHeaderProducer(token);

// Custom decoder until we fix the problem in the io-utils generator
// https://www.pivotaltracker.com/story/show/169915207
// tslint:disable-next-line:typedef
function startEmailValidationProcessCustomDecoder() {
return composeResponseDecoders(
composeResponseDecoders(
composeResponseDecoders(
composeResponseDecoders(
constantResponseDecoder<undefined, 202>(202, undefined),
ioResponseDecoder<
400,
typeof ProblemJson["_A"],
typeof ProblemJson["_O"]
>(400, ProblemJson)
),
constantResponseDecoder<undefined, 401>(401, undefined)
),
constantResponseDecoder<undefined, 404>(404, undefined)
),
constantResponseDecoder<undefined, 429>(429, undefined)
);
}

const getProfileT: ReplaceRequestParams<
GetProfileT,
Omit<RequestParams<GetProfileT>, "SubscriptionKey">
> = {
headers: tokenHeaderProducer,
method: "get",
query: _ => ({}),
response_decoder: getProfileDefaultDecoder(),
url: params => `/profiles/${params.fiscalCode}`
};

const createProfileT: ReplaceRequestParams<
CreateProfileT,
Omit<RequestParams<CreateProfileT>, "SubscriptionKey">
> = {
body: params => JSON.stringify(params.newProfile),
headers: composeHeaderProducers(tokenHeaderProducer, ApiHeaderJson),
method: "post",
query: _ => ({}),
response_decoder: createProfileDefaultDecoder(),
url: params => `/profiles/${params.fiscalCode}`
};

const updateProfileT: ReplaceRequestParams<
UpdateProfileT,
Omit<RequestParams<UpdateProfileT>, "SubscriptionKey">
> = {
body: params => JSON.stringify(params.profile),
headers: composeHeaderProducers(tokenHeaderProducer, ApiHeaderJson),
method: "put",
query: _ => ({}),
response_decoder: updateProfileDefaultDecoder(),
url: params => `/profiles/${params.fiscalCode}`
};

const emailValidationProcessT: ReplaceRequestParams<
StartEmailValidationProcessT,
Omit<RequestParams<StartEmailValidationProcessT>, "SubscriptionKey">
> = {
body: _ => "{}",
headers: composeHeaderProducers(tokenHeaderProducer, ApiHeaderJson),
method: "post",
query: _ => ({}),
response_decoder: startEmailValidationProcessCustomDecoder(),
url: params => `/email-validation-process/${params.fiscalCode}`
};

const getUserDataProcessingT: ReplaceRequestParams<
GetUserDataProcessingT,
Omit<RequestParams<GetUserDataProcessingT>, "SubscriptionKey">
> = {
headers: tokenHeaderProducer,
method: "get",
query: _ => ({}),
response_decoder: getUserDataProcessingDefaultDecoder(),
url: params =>
`/user-data-processing/${params.fiscalCode}/${params.userDataProcessingChoiceParam}`
};

const getMessagesT: ReplaceRequestParams<
GetMessagesByUserT,
Omit<RequestParams<GetMessagesByUserT>, "SubscriptionKey">
> = {
headers: tokenHeaderProducer,
method: "get",
query: _ => ({}),
response_decoder: getMessagesByUserDefaultDecoder(),
url: params => `/messages/${params.fiscalCode}`
};

const getMessageT: ReplaceRequestParams<
GetMessageT,
Omit<RequestParams<GetMessageT>, "SubscriptionKey">
> = {
headers: tokenHeaderProducer,
method: "get",
query: _ => ({}),
response_decoder: getMessageDefaultDecoder(),
url: params => `/messages/${params.fiscalCode}/${params.id}`
};

const getVisibleServicesT: ReplaceRequestParams<
GetVisibleServicesT,
Omit<RequestParams<GetVisibleServicesT>, "SubscriptionKey">
> = {
headers: tokenHeaderProducer,
method: "get",
query: _ => ({}),
response_decoder: getVisibleServicesDefaultDecoder(),
url: () => `/services`
};

const getServiceT: ReplaceRequestParams<
GetServiceT,
Omit<RequestParams<GetServiceT>, "SubscriptionKey">
> = {
headers: tokenHeaderProducer,
method: "get",
query: _ => ({}),
response_decoder: getServiceDefaultDecoder(),
url: params => `/services/${params.service_id}`
};

const upsertUserDataProcessingT: ReplaceRequestParams<
UpsertUserDataProcessingT,
Omit<RequestParams<UpsertUserDataProcessingT>, "SubscriptionKey">
> = {
body: params => JSON.stringify(params.userDataProcessingChoiceRequest),
headers: composeHeaderProducers(tokenHeaderProducer, ApiHeaderJson),
method: "post",
query: _ => ({}),
response_decoder: upsertUserDataProcessingDefaultDecoder(),
url: params => `/user-data-processing/${params.fiscalCode}`
};

return {
createProfile: createFetchRequestForApi(createProfileT, options),
emailValidationProcess: createFetchRequestForApi(
emailValidationProcessT,
options
),
getMessage: createFetchRequestForApi(getMessageT, options),
getMessages: createFetchRequestForApi(getMessagesT, options),
getProfile: createFetchRequestForApi(getProfileT, options),
getService: createFetchRequestForApi(getServiceT, options),
getUserDataProcessing: createFetchRequestForApi(
getUserDataProcessingT,
options
),
getVisibleServices: createFetchRequestForApi(getVisibleServicesT, options),
updateProfile: createFetchRequestForApi(updateProfileT, options),
upsertUserDataProcessing: createFetchRequestForApi(
upsertUserDataProcessingT,
options
)
};
fetchApi,
withDefaults: op => params =>
op({
...params,
SubscriptionKey: token
})
});
}

export type APIClient = typeof APIClient;
6 changes: 3 additions & 3 deletions src/clients/bonus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export function BonusAPIClient(
method: "get",
query: _ => ({}),
response_decoder: getBonusEligibilityCheckDefaultDecoder(),
url: params => `/bonus/vacanze/eligibility/${params.fiscalCode}`
url: params => `/bonus/vacanze/eligibility/${params.fiscalcode}`
};

const getLatestBonusActivationByIdT: ReplaceRequestParams<
Expand All @@ -105,7 +105,7 @@ export function BonusAPIClient(
query: _ => ({}),
response_decoder: getLatestBonusActivationByIdDefaultDecoder(),
url: params =>
`/bonus/vacanze/activations/${params.fiscalCode}/${params.bonus_id}`
`/bonus/vacanze/activations/${params.fiscalcode}/${params.bonus_id}`
};

const getAllBonusActivationsT: ReplaceRequestParams<
Expand All @@ -116,7 +116,7 @@ export function BonusAPIClient(
method: "get",
query: _ => ({}),
response_decoder: getAllBonusActivationsDefaultDecoder(),
url: params => `/bonus/vacanze/activations/${params.fiscalCode}`
url: params => `/bonus/vacanze/activations/${params.fiscalcode}`
};

// This request type need to be rewritten because the code generator doesn't handle custom response header values
Expand Down
6 changes: 3 additions & 3 deletions src/clients/pagopa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function PagoPAClient(
};

const activatePayment: ActivatePaymentT = {
body: params => JSON.stringify(params.paymentActivationsPostRequest),
body: params => JSON.stringify(params.body),
headers: ApiHeaderJson,
method: "post",
query: _ => ({}),
Expand All @@ -42,15 +42,15 @@ export function PagoPAClient(
method: "get",
query: _ => ({}),
response_decoder: getActivationStatusDefaultDecoder(),
url: params => `/payment-activations/${params.codiceContestoPagamento}`
url: params => `/payment-activations/${params.codice_contesto_pagamento}`
};

const getPaymentInfo: GetPaymentInfoT = {
headers: () => ({}),
method: "get",
query: _ => ({}),
response_decoder: getPaymentInfoDefaultDecoder(),
url: params => `/payment-requests/${params.rptId}`
url: params => `/payment-requests/${params.rpt_id_from_string}`
};

return {
Expand Down
4 changes: 2 additions & 2 deletions src/controllers/__tests__/bonusController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const aInstanceId: InstanceId = {

const aEligibilityCheck: EligibilityCheck = {
dsu_request: {
dsu_created_at: new Date().toString(),
dsu_created_at: new Date(),
dsu_protocol_id: "123" as NonEmptyString,
family_members: [],
has_discrepancies: false,
Expand All @@ -75,7 +75,7 @@ const aBonusActivation: BonusActivation = {
applicant_fiscal_code: aFiscalCode,
created_at: aDate,
dsu_request: {
dsu_created_at: "",
dsu_created_at: new Date(),
dsu_protocol_id: "dsuprotid" as NonEmptyString,
family_members: [
{ fiscal_code: aFiscalCode, name: aValidName, surname: aValidFamilyname }
Expand Down
Loading