From 13cd93338fde14ecb7bc6293add88e5a3168fd3b Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Tue, 21 May 2024 13:51:57 +0300 Subject: [PATCH] apps/web: pass token to GraphQL query (SSR) --- apps/web/apollo/client.js | 10 +- apps/web/apollo/link.js | 170 ++++++++++++++++++--------------- apps/web/pages/admin/cache.jsx | 2 +- apps/web/pages/index.jsx | 2 +- apps/web/pages/unlimited.jsx | 2 +- apps/web/utils/auth.ts | 12 +++ 6 files changed, 112 insertions(+), 86 deletions(-) create mode 100644 apps/web/utils/auth.ts diff --git a/apps/web/apollo/client.js b/apps/web/apollo/client.js index b6cc104..cb3b5fd 100644 --- a/apps/web/apollo/client.js +++ b/apps/web/apollo/client.js @@ -1,20 +1,20 @@ -import { link } from './link'; +import { createLink } from './link'; import { ApolloClient, InMemoryCache } from '@apollo/client'; import { isServer } from 'tools/common'; /** @type {import('@apollo/client').ApolloClient} */ let apolloClient; -function createApolloClient() { +function createApolloClient(headers) { return new ApolloClient({ cache: new InMemoryCache(), - link, + link: createLink(headers), ssrMode: isServer(), }); } -export default function initializeApollo(initialState = null) { - const _apolloClient = apolloClient ?? createApolloClient(); +export default function initializeApollo(initialState, headers) { + const _apolloClient = apolloClient ?? createApolloClient(headers); // If your page has Next.js data fetching methods that use Apollo Client, the initial state // gets hydrated here diff --git a/apps/web/apollo/link.js b/apps/web/apollo/link.js index 2363d5c..1d94c11 100644 --- a/apps/web/apollo/link.js +++ b/apps/web/apollo/link.js @@ -2,6 +2,7 @@ import { message } from '@/Components/Common/Notification'; import { publicRuntimeConfigSchema } from '@/config/schema/runtime-config'; import getUrls from '@/config/urls'; +import { getToken } from '@/utils/auth'; import { ApolloLink, from, HttpLink } from '@apollo/client'; import { setContext } from '@apollo/client/link/context'; import { onError } from '@apollo/client/link/error'; @@ -9,102 +10,115 @@ import { getCurrentScope } from '@sentry/nextjs'; import getConfig from 'next/config'; import { isServer } from 'tools'; -const { URL_CRM_GRAPHQL } = getUrls(); +export function createLink(headers) { + const { URL_CRM_GRAPHQL } = getUrls(); -const modifyDataLink = new ApolloLink((operation, forward) => { - const context = operation?.getContext(); + const modifyDataLink = new ApolloLink((operation, forward) => { + const context = operation?.getContext(); - return forward(operation).map((response) => { - if (!context?.disableModify) { - if (Object.keys(response?.data).includes('evo_addproduct_types')) { - response.data.evo_addproduct_types = response.data.evo_addproduct_types.map( - (evo_addproduct_type) => { - if (evo_addproduct_type.evo_graph_price) + return forward(operation).map((response) => { + if (!context?.disableModify) { + if (Object.keys(response?.data).includes('evo_addproduct_types')) { + response.data.evo_addproduct_types = response.data.evo_addproduct_types.map( + (evo_addproduct_type) => { + if (evo_addproduct_type.evo_graph_price) + return { + ...evo_addproduct_type, + label: `${evo_addproduct_type.label} (${evo_addproduct_type.evo_graph_price} руб.)`, + }; + + return evo_addproduct_type; + } + ); + } + + if (Object.keys(response?.data).includes('evo_equipments')) { + response.data.evo_equipments = response.data.evo_equipments.map((evo_equipment) => { + if (evo_equipment.evo_start_production_year) return { - ...evo_addproduct_type, - label: `${evo_addproduct_type.label} (${evo_addproduct_type.evo_graph_price} руб.)`, + ...evo_equipment, + label: `${evo_equipment.label} (${evo_equipment.evo_start_production_year})`, }; - return evo_addproduct_type; - } - ); + return evo_equipment; + }); + } + + if (operation.operationName === 'GetInsuranceCompanies') { + response.data.accounts = response.data.accounts.map((account) => { + const substring = account.label.match(/"(.+)"/u); + if (substring) + return { + ...account, + label: substring ? substring[1].replaceAll('"', '').trim() : account.label, + }; + + return account; + }); + } } - if (Object.keys(response?.data).includes('evo_equipments')) { - response.data.evo_equipments = response.data.evo_equipments.map((evo_equipment) => { - if (evo_equipment.evo_start_production_year) - return { - ...evo_equipment, - label: `${evo_equipment.label} (${evo_equipment.evo_start_production_year})`, - }; + return response; + }); + }); - return evo_equipment; - }); - } + const httpLink = new HttpLink({ + uri: URL_CRM_GRAPHQL, + }); - if (operation.operationName === 'GetInsuranceCompanies') { - response.data.accounts = response.data.accounts.map((account) => { - const substring = account.label.match(/"(.+)"/u); - if (substring) - return { - ...account, - label: substring ? substring[1].replaceAll('"', '').trim() : account.label, - }; + const authLink = setContext((_, { headers: existingHeaders }) => { + if (process.env.NODE_ENV === 'development') { + const { publicRuntimeConfig } = getConfig(); + const { DEV_AUTH_TOKEN } = publicRuntimeConfigSchema.parse(publicRuntimeConfig); - return account; - }); - } + if (DEV_AUTH_TOKEN) + return { + headers: { + ...existingHeaders, + authorization: `Bearer ${DEV_AUTH_TOKEN}`, + }, + }; } - return response; - }); -}); + if (isServer()) { + const token = getToken({ headers }); -const httpLink = new HttpLink({ - uri: URL_CRM_GRAPHQL, -}); - -const authLink = setContext((_, { headers: existingHeaders }) => { - if (process.env.NODE_ENV === 'development') { - const { publicRuntimeConfig } = getConfig(); - const { DEV_AUTH_TOKEN } = publicRuntimeConfigSchema.parse(publicRuntimeConfig); - - if (DEV_AUTH_TOKEN) return { headers: { ...existingHeaders, - authorization: `Bearer ${DEV_AUTH_TOKEN}`, + authorization: `Bearer ${token}`, }, }; - } + } - return { - headers: { - ...existingHeaders, - }, - }; -}); - -const key = 'APOLLO_GRAPHQL'; - -const errorLink = onError(({ graphQLErrors, networkError, operation, response }) => { - const scope = getCurrentScope(); - scope.setTag('operationName', operation.operationName); - - if (!isServer()) { - message.error({ - content: `Ошибка во время загрузки данных из CRM`, - key, - onClick: () => message.destroy(key), - }); - } - - scope.setExtras({ - graphQLErrors, - networkError, - operation, - response, + return { + headers: { + ...existingHeaders, + }, + }; }); -}); -export const link = from([authLink, errorLink, modifyDataLink, httpLink]); + const key = 'APOLLO_GRAPHQL'; + + const errorLink = onError(({ graphQLErrors, networkError, operation, response }) => { + const scope = getCurrentScope(); + scope.setTag('operationName', operation.operationName); + + if (!isServer()) { + message.error({ + content: `Ошибка во время загрузки данных из CRM`, + key, + onClick: () => message.destroy(key), + }); + } + + scope.setExtras({ + graphQLErrors, + networkError, + operation, + response, + }); + }); + + return from([authLink, errorLink, modifyDataLink, httpLink]); +} diff --git a/apps/web/pages/admin/cache.jsx b/apps/web/pages/admin/cache.jsx index 919fdb6..8f09c3e 100644 --- a/apps/web/pages/admin/cache.jsx +++ b/apps/web/pages/admin/cache.jsx @@ -29,7 +29,7 @@ export async function getServerSideProps({ req }) { const { cookie = '' } = req.headers; const queryClient = new QueryClient(); - const apolloClient = initializeApollo(); + const apolloClient = initializeApollo(null, { cookie }); const getUserType = makeGetUserType({ apolloClient, queryClient }); try { diff --git a/apps/web/pages/index.jsx b/apps/web/pages/index.jsx index 737b129..6e23220 100644 --- a/apps/web/pages/index.jsx +++ b/apps/web/pages/index.jsx @@ -36,7 +36,7 @@ export async function getServerSideProps({ req }) { const { cookie = '' } = req.headers; const queryClient = new QueryClient(); - const apolloClient = initializeApollo(); + const apolloClient = initializeApollo(null, { cookie }); const getUserType = makeGetUserType({ apolloClient, queryClient }); try { diff --git a/apps/web/pages/unlimited.jsx b/apps/web/pages/unlimited.jsx index 7b7fc0e..8ae0416 100644 --- a/apps/web/pages/unlimited.jsx +++ b/apps/web/pages/unlimited.jsx @@ -37,7 +37,7 @@ export async function getServerSideProps({ req }) { const { cookie = '' } = req.headers; const queryClient = new QueryClient(); - const apolloClient = initializeApollo(); + const apolloClient = initializeApollo(null, { cookie }); const getUserType = makeGetUserType({ apolloClient, queryClient }); try { diff --git a/apps/web/utils/auth.ts b/apps/web/utils/auth.ts new file mode 100644 index 0000000..fffa1b5 --- /dev/null +++ b/apps/web/utils/auth.ts @@ -0,0 +1,12 @@ +import type { IncomingHttpHeaders } from 'http'; + +type Request = { + headers: IncomingHttpHeaders; +}; + +export function getToken({ headers }: Request) { + return headers.cookie + ?.split(';') + .find((c) => c.trim().startsWith('token=')) + ?.split('=')[1]; +}