apps/web: pass token to GraphQL query (SSR)

This commit is contained in:
vchikalkin 2024-05-21 13:51:57 +03:00
parent 7d5be83e4c
commit 13cd93338f
6 changed files with 112 additions and 86 deletions

View File

@ -1,20 +1,20 @@
import { link } from './link'; import { createLink } from './link';
import { ApolloClient, InMemoryCache } from '@apollo/client'; import { ApolloClient, InMemoryCache } from '@apollo/client';
import { isServer } from 'tools/common'; import { isServer } from 'tools/common';
/** @type {import('@apollo/client').ApolloClient<import('@apollo/client').NormalizedCacheObject>} */ /** @type {import('@apollo/client').ApolloClient<import('@apollo/client').NormalizedCacheObject>} */
let apolloClient; let apolloClient;
function createApolloClient() { function createApolloClient(headers) {
return new ApolloClient({ return new ApolloClient({
cache: new InMemoryCache(), cache: new InMemoryCache(),
link, link: createLink(headers),
ssrMode: isServer(), ssrMode: isServer(),
}); });
} }
export default function initializeApollo(initialState = null) { export default function initializeApollo(initialState, headers) {
const _apolloClient = apolloClient ?? createApolloClient(); const _apolloClient = apolloClient ?? createApolloClient(headers);
// If your page has Next.js data fetching methods that use Apollo Client, the initial state // If your page has Next.js data fetching methods that use Apollo Client, the initial state
// gets hydrated here // gets hydrated here

View File

@ -2,6 +2,7 @@
import { message } from '@/Components/Common/Notification'; import { message } from '@/Components/Common/Notification';
import { publicRuntimeConfigSchema } from '@/config/schema/runtime-config'; import { publicRuntimeConfigSchema } from '@/config/schema/runtime-config';
import getUrls from '@/config/urls'; import getUrls from '@/config/urls';
import { getToken } from '@/utils/auth';
import { ApolloLink, from, HttpLink } from '@apollo/client'; import { ApolloLink, from, HttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context'; import { setContext } from '@apollo/client/link/context';
import { onError } from '@apollo/client/link/error'; import { onError } from '@apollo/client/link/error';
@ -9,102 +10,115 @@ import { getCurrentScope } from '@sentry/nextjs';
import getConfig from 'next/config'; import getConfig from 'next/config';
import { isServer } from 'tools'; 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 modifyDataLink = new ApolloLink((operation, forward) => {
const context = operation?.getContext(); const context = operation?.getContext();
return forward(operation).map((response) => { return forward(operation).map((response) => {
if (!context?.disableModify) { if (!context?.disableModify) {
if (Object.keys(response?.data).includes('evo_addproduct_types')) { if (Object.keys(response?.data).includes('evo_addproduct_types')) {
response.data.evo_addproduct_types = response.data.evo_addproduct_types.map( response.data.evo_addproduct_types = response.data.evo_addproduct_types.map(
(evo_addproduct_type) => { (evo_addproduct_type) => {
if (evo_addproduct_type.evo_graph_price) 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 { return {
...evo_addproduct_type, ...evo_equipment,
label: `${evo_addproduct_type.label} (${evo_addproduct_type.evo_graph_price} руб.)`, 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')) { return response;
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 evo_equipment; const httpLink = new HttpLink({
}); uri: URL_CRM_GRAPHQL,
} });
if (operation.operationName === 'GetInsuranceCompanies') { const authLink = setContext((_, { headers: existingHeaders }) => {
response.data.accounts = response.data.accounts.map((account) => { if (process.env.NODE_ENV === 'development') {
const substring = account.label.match(/"(.+)"/u); const { publicRuntimeConfig } = getConfig();
if (substring) const { DEV_AUTH_TOKEN } = publicRuntimeConfigSchema.parse(publicRuntimeConfig);
return {
...account,
label: substring ? substring[1].replaceAll('"', '').trim() : account.label,
};
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 { return {
headers: { headers: {
...existingHeaders, ...existingHeaders,
authorization: `Bearer ${DEV_AUTH_TOKEN}`, authorization: `Bearer ${token}`,
}, },
}; };
} }
return { return {
headers: { headers: {
...existingHeaders, ...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,
}); });
});
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]);
}

View File

@ -29,7 +29,7 @@ export async function getServerSideProps({ req }) {
const { cookie = '' } = req.headers; const { cookie = '' } = req.headers;
const queryClient = new QueryClient(); const queryClient = new QueryClient();
const apolloClient = initializeApollo(); const apolloClient = initializeApollo(null, { cookie });
const getUserType = makeGetUserType({ apolloClient, queryClient }); const getUserType = makeGetUserType({ apolloClient, queryClient });
try { try {

View File

@ -36,7 +36,7 @@ export async function getServerSideProps({ req }) {
const { cookie = '' } = req.headers; const { cookie = '' } = req.headers;
const queryClient = new QueryClient(); const queryClient = new QueryClient();
const apolloClient = initializeApollo(); const apolloClient = initializeApollo(null, { cookie });
const getUserType = makeGetUserType({ apolloClient, queryClient }); const getUserType = makeGetUserType({ apolloClient, queryClient });
try { try {

View File

@ -37,7 +37,7 @@ export async function getServerSideProps({ req }) {
const { cookie = '' } = req.headers; const { cookie = '' } = req.headers;
const queryClient = new QueryClient(); const queryClient = new QueryClient();
const apolloClient = initializeApollo(); const apolloClient = initializeApollo(null, { cookie });
const getUserType = makeGetUserType({ apolloClient, queryClient }); const getUserType = makeGetUserType({ apolloClient, queryClient });
try { try {

12
apps/web/utils/auth.ts Normal file
View File

@ -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];
}