apps/web: create api/crm/graphql
This commit is contained in:
parent
5d1aa99d75
commit
00378ece8d
62
apps/web/config/graphql/ttl.ts
Normal file
62
apps/web/config/graphql/ttl.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { seconds } from '@/utils/time';
|
||||
|
||||
export const queryTTL: Record<string, number | false> = {
|
||||
GetAddProductType: seconds().fromHours(12),
|
||||
GetAddproductTypes: seconds().fromHours(12),
|
||||
GetAgent: seconds().fromHours(12),
|
||||
GetBrand: seconds().fromHours(3),
|
||||
GetBrands: seconds().fromHours(3),
|
||||
GetCoefficients: seconds().fromHours(12),
|
||||
GetConfiguration: seconds().fromHours(3),
|
||||
GetConfigurations: seconds().fromMinutes(15),
|
||||
GetCurrencyChanges: seconds().fromHours(1),
|
||||
GetDealer: seconds().fromHours(1),
|
||||
GetDealerPerson: seconds().fromHours(1),
|
||||
GetDealerPersons: seconds().fromHours(1),
|
||||
GetDealers: seconds().fromMinutes(15),
|
||||
GetFuelCards: seconds().fromHours(12),
|
||||
GetGPSBrands: seconds().fromHours(24),
|
||||
GetGPSModels: seconds().fromHours(24),
|
||||
GetImportProgram: seconds().fromHours(12),
|
||||
GetInsNSIBTypes: seconds().fromHours(12),
|
||||
GetInsuranceCompanies: seconds().fromHours(12),
|
||||
GetInsuranceCompany: seconds().fromHours(12),
|
||||
GetLead: false,
|
||||
GetLeadUrl: seconds().fromHours(12),
|
||||
GetLeads: false,
|
||||
GetLeaseObjectType: seconds().fromHours(24),
|
||||
GetLeaseObjectTypes: seconds().fromHours(24),
|
||||
GetLeasingWithoutKaskoTypes: seconds().fromHours(12),
|
||||
GetModel: seconds().fromHours(3),
|
||||
GetModels: seconds().fromMinutes(15),
|
||||
GetOpportunities: false,
|
||||
GetOpportunity: false,
|
||||
GetOpportunityUrl: seconds().fromHours(12),
|
||||
GetProduct: seconds().fromHours(12),
|
||||
GetProducts: seconds().fromHours(12),
|
||||
GetQuote: false,
|
||||
GetQuoteData: false,
|
||||
GetQuoteUrl: seconds().fromHours(12),
|
||||
GetQuotes: false,
|
||||
GetRate: seconds().fromHours(12),
|
||||
GetRates: seconds().fromHours(12),
|
||||
GetRegion: seconds().fromHours(24),
|
||||
GetRegions: seconds().fromHours(24),
|
||||
GetRegistrationTypes: seconds().fromHours(12),
|
||||
GetRewardCondition: seconds().fromHours(1),
|
||||
GetRewardConditions: seconds().fromHours(1),
|
||||
GetRoles: seconds().fromHours(12),
|
||||
GetSotCoefficientType: seconds().fromHours(12),
|
||||
GetSubsidies: seconds().fromHours(12),
|
||||
GetSubsidy: seconds().fromHours(12),
|
||||
GetSystemUser: seconds().fromHours(12),
|
||||
GetTarif: seconds().fromHours(12),
|
||||
GetTarifs: seconds().fromHours(12),
|
||||
GetTechnicalCards: seconds().fromHours(12),
|
||||
GetTelematicTypes: seconds().fromHours(12),
|
||||
GetTown: seconds().fromHours(24),
|
||||
GetTowns: seconds().fromHours(24),
|
||||
GetTrackerTypes: seconds().fromHours(12),
|
||||
GetTransactionCurrencies: seconds().fromHours(12),
|
||||
GetTransactionCurrency: seconds().fromHours(12),
|
||||
};
|
||||
@ -3,6 +3,11 @@ const { z } = require('zod');
|
||||
const envSchema = z.object({
|
||||
BASE_PATH: z.string().optional().default(''),
|
||||
PORT: z.string().optional(),
|
||||
REDIS_HOST: z.string(),
|
||||
REDIS_PORT: z
|
||||
.string()
|
||||
.transform((val) => Number.parseInt(val, 10))
|
||||
.default('6379'),
|
||||
SENTRY_AUTH_TOKEN: z.string(),
|
||||
SENTRY_DSN: z.string(),
|
||||
SENTRY_ENVIRONMENT: z.string(),
|
||||
@ -16,7 +21,6 @@ const envSchema = z.object({
|
||||
URL_CRM_CREATEKP_DIRECT: z.string(),
|
||||
URL_CRM_DOWNLOADKP_BASE: z.string(),
|
||||
URL_CRM_GRAPHQL_DIRECT: z.string(),
|
||||
URL_CRM_GRAPHQL_PROXY: z.string().default('http://api:3001/proxy/graphql'),
|
||||
URL_ELT_KASKO_DIRECT: z.string(),
|
||||
URL_ELT_OSAGO_DIRECT: z.string(),
|
||||
URL_GET_USER_DIRECT: z.string(),
|
||||
|
||||
@ -21,7 +21,7 @@ function getUrls() {
|
||||
PORT,
|
||||
URL_ELT_KASKO_DIRECT,
|
||||
URL_ELT_OSAGO_DIRECT,
|
||||
URL_CRM_GRAPHQL_PROXY,
|
||||
URL_CRM_GRAPHQL_DIRECT,
|
||||
URL_CACHE_GET_QUERIES_DIRECT,
|
||||
URL_CACHE_DELETE_QUERY_DIRECT,
|
||||
URL_CACHE_RESET_QUERIES_DIRECT,
|
||||
@ -41,7 +41,7 @@ function getUrls() {
|
||||
URL_CORE_FINGAP: URL_CORE_FINGAP_DIRECT,
|
||||
URL_CRM_CREATEKP: URL_CRM_CREATEKP_DIRECT,
|
||||
URL_CRM_DOWNLOADKP: withBasePath(urls.URL_CRM_DOWNLOADKP_PROXY),
|
||||
URL_CRM_GRAPHQL: URL_CRM_GRAPHQL_PROXY,
|
||||
URL_CRM_GRAPHQL: URL_CRM_GRAPHQL_DIRECT,
|
||||
URL_ELT_KASKO: URL_ELT_KASKO_DIRECT,
|
||||
URL_ELT_OSAGO: URL_ELT_OSAGO_DIRECT,
|
||||
URL_GET_USER: URL_GET_USER_DIRECT,
|
||||
|
||||
@ -8,7 +8,7 @@ module.exports = {
|
||||
URL_CORE_FINGAP_PROXY: '/api/core/fingap',
|
||||
URL_CRM_CREATEKP_PROXY: '/api/crm/create-kp',
|
||||
URL_CRM_DOWNLOADKP_PROXY: '/api/crm/download-kp',
|
||||
URL_CRM_GRAPHQL_PROXY: '/api/graphql/crm',
|
||||
URL_CRM_GRAPHQL_PROXY: '/api/crm/graphql',
|
||||
URL_ELT_KASKO_PROXY: '/api/elt/kasko',
|
||||
URL_ELT_OSAGO_PROXY: '/api/elt/osago',
|
||||
URL_GET_USER_PROXY: '/api/auth/user',
|
||||
|
||||
@ -49,10 +49,6 @@ module.exports = withSentryConfig(
|
||||
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
destination: env.URL_CRM_GRAPHQL_PROXY + '/:path*',
|
||||
source: urls.URL_CRM_GRAPHQL_PROXY + '/:path*',
|
||||
},
|
||||
{
|
||||
destination: env.URL_CRM_DOWNLOADKP_BASE + '/:path*',
|
||||
source: urls.URL_CRM_DOWNLOADKP_PROXY + '/:path*',
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"@trpc/server": "^10.45.1",
|
||||
"axios": "^1.6.7",
|
||||
"dayjs": "^1.11.10",
|
||||
"ioredis": "^5.3.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"modern-normalize": "^2.0.0",
|
||||
|
||||
50
apps/web/pages/api/crm/graphql.ts
Normal file
50
apps/web/pages/api/crm/graphql.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { queryTTL } from '@/config/graphql/ttl';
|
||||
import getUrls from '@/config/urls';
|
||||
import { createRedisInstance } from '@/redis/client';
|
||||
import { HttpError } from '@/utils/error';
|
||||
import type { ApolloQueryResult, GraphQLRequest } from '@apollo/client';
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
|
||||
const { URL_CRM_GRAPHQL } = getUrls();
|
||||
|
||||
const redis = createRedisInstance();
|
||||
|
||||
function getHeaders(req: NextApiRequest) {
|
||||
const headers = new Headers();
|
||||
Object.keys(req.headers).forEach((key) => {
|
||||
const value = req.headers[key];
|
||||
if (value !== undefined && typeof value === 'string') headers.set(key, value);
|
||||
});
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const headers = getHeaders(req);
|
||||
|
||||
const { operationName, variables } = req.body as GraphQLRequest;
|
||||
const key = `${operationName} ${JSON.stringify(variables)}`;
|
||||
const cached = await redis.get(key);
|
||||
|
||||
if (cached) return res.send({ ...JSON.parse(cached), cached: true });
|
||||
|
||||
const response = await fetch(URL_CRM_GRAPHQL, {
|
||||
body: JSON.stringify(req.body),
|
||||
headers,
|
||||
method: req.method,
|
||||
});
|
||||
|
||||
const data = (await response.json()) as ApolloQueryResult<unknown>;
|
||||
|
||||
if (!response.ok || data?.error || data?.errors?.length) {
|
||||
throw new HttpError(response.statusText, response.status || 500);
|
||||
}
|
||||
|
||||
if (operationName) {
|
||||
const ttl = queryTTL[operationName];
|
||||
|
||||
if (data && ttl !== false) await redis.set(key, JSON.stringify(data), 'EX', ttl);
|
||||
}
|
||||
|
||||
return res.send(data);
|
||||
}
|
||||
36
apps/web/redis/client.ts
Normal file
36
apps/web/redis/client.ts
Normal file
@ -0,0 +1,36 @@
|
||||
/* eslint-disable no-console */
|
||||
import envSchema from '@/config/schema/env';
|
||||
import type { RedisOptions } from 'ioredis';
|
||||
import { Redis } from 'ioredis';
|
||||
|
||||
const { REDIS_HOST, REDIS_PORT } = envSchema.parse(process.env);
|
||||
|
||||
export function createRedisInstance() {
|
||||
try {
|
||||
const options: RedisOptions = {
|
||||
enableAutoPipelining: true,
|
||||
host: REDIS_HOST,
|
||||
lazyConnect: true,
|
||||
maxRetriesPerRequest: 0,
|
||||
port: REDIS_PORT,
|
||||
retryStrategy: (times: number) => {
|
||||
if (times > 3) {
|
||||
throw new Error(`[Redis] Could not connect after ${times} attempts`);
|
||||
}
|
||||
|
||||
return Math.min(times * 200, 1000);
|
||||
},
|
||||
showFriendlyErrorStack: true,
|
||||
};
|
||||
|
||||
const redis = new Redis(options);
|
||||
|
||||
redis.on('error', (error: unknown) => {
|
||||
console.warn('[Redis] Error connecting', error);
|
||||
});
|
||||
|
||||
return redis;
|
||||
} catch (error) {
|
||||
throw new Error(`[Redis] Could not create a Redis instance. ${error}`);
|
||||
}
|
||||
}
|
||||
13
apps/web/utils/time.ts
Normal file
13
apps/web/utils/time.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export function seconds() {
|
||||
return {
|
||||
fromDays(days: number) {
|
||||
return days * 24 * 60 * 60;
|
||||
},
|
||||
fromHours(hours: number) {
|
||||
return hours * 60 * 60;
|
||||
},
|
||||
fromMinutes(minutes: number) {
|
||||
return minutes * 60;
|
||||
},
|
||||
};
|
||||
}
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@ -156,6 +156,9 @@ importers:
|
||||
dayjs:
|
||||
specifier: ^1.11.10
|
||||
version: 1.11.10
|
||||
ioredis:
|
||||
specifier: ^5.3.2
|
||||
version: 5.3.2
|
||||
mobx:
|
||||
specifier: ^6.12.0
|
||||
version: 6.12.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user