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
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ COPY /api_pagopa.yaml /usr/src/app/api_pagopa.yaml
COPY /api_public.yaml /usr/src/app/api_public.yaml
COPY /api_bonus.yaml /usr/src/app/api_bonus.yaml
COPY /api_session.yaml /usr/src/app/api_session.yaml
COPY /api_myportal.yaml /usr/src/app/api_myportal.yaml
COPY /api_bpd.yaml /usr/src/app/api_bpd.yaml

COPY /.npmrc /usr/src/app/.npmrc
RUN sudo chmod -R 777 /usr/src/app \
Expand Down
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@
"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:auth-models": "rimraf generated/auth && shx mkdir -p generated/auth && gen-api-models --api-spec api_auth.yaml --out-dir generated/auth",
"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:auth-models": "rimraf generated/auth && gen-api-models --api-spec api_auth.yaml --out-dir generated/auth",
"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 --client",
"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 --client",
"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 @@ -119,7 +119,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
239 changes: 11 additions & 228 deletions src/clients/api.ts
Original file line number Diff line number Diff line change
@@ -1,239 +1,22 @@
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";

// 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>(
token: string
): RequestHeaderProducer<P, "X-Functions-Key" | "Ocp-Apim-Subscription-Key"> {
return () => ({
"Ocp-Apim-Subscription-Key": token,
"X-Functions-Key": token
});
}
import { Client, createClient } from "../../generated/io-api/client";

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;
Loading