init
This commit is contained in:
109
packages/server/src/api.ts
Normal file
109
packages/server/src/api.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import fastifyCors from '@fastify/cors';
|
||||
import fastifySwagger from '@fastify/swagger';
|
||||
import fastify from 'fastify';
|
||||
import {
|
||||
hasZodFastifySchemaValidationErrors,
|
||||
isResponseSerializationError,
|
||||
jsonSchemaTransform,
|
||||
serializerCompiler,
|
||||
validatorCompiler,
|
||||
type ZodTypeProvider,
|
||||
} from 'fastify-type-provider-zod';
|
||||
|
||||
import { Services } from './utils/utils.services.ts';
|
||||
import { systemEndpoints } from './endpoints/system/system.ts';
|
||||
import { WarmupService } from './services/warmup/warmup.ts';
|
||||
import { documentEndpoints } from './endpoints/documents/documents.ts';
|
||||
import { documentFilterEndpoints } from './endpoints/document-filters/document-filters.ts';
|
||||
import { documentChunkFilterEndpoints } from './endpoints/document-chunk-filters/document-chunk-filters.ts';
|
||||
|
||||
class BaseError extends Error {
|
||||
public statusCode: number;
|
||||
constructor(message: string, statusCode = 500) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
}
|
||||
|
||||
const createApi = async (services: Services = new Services()) => {
|
||||
const app = fastify().withTypeProvider<ZodTypeProvider>();
|
||||
app.setValidatorCompiler(validatorCompiler);
|
||||
app.setSerializerCompiler(serializerCompiler);
|
||||
|
||||
app.decorate('services', services);
|
||||
|
||||
app.register(fastifyCors);
|
||||
app.register(fastifySwagger, {
|
||||
openapi: {
|
||||
info: {
|
||||
title: 'My API',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
transform: jsonSchemaTransform,
|
||||
});
|
||||
|
||||
await app.register(import('@scalar/fastify-api-reference'), {
|
||||
routePrefix: '/docs',
|
||||
});
|
||||
|
||||
app.setErrorHandler((err, req, reply) => {
|
||||
console.error(err);
|
||||
if (hasZodFastifySchemaValidationErrors(err)) {
|
||||
return reply.code(400).send({
|
||||
error: 'Response Validation Error',
|
||||
message: "Request doesn't match the schema",
|
||||
statusCode: 400,
|
||||
details: {
|
||||
issues: err.validation,
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (isResponseSerializationError(err)) {
|
||||
return reply.code(500).send({
|
||||
error: 'Internal Server Error',
|
||||
message: "Response doesn't match the schema",
|
||||
statusCode: 500,
|
||||
details: {
|
||||
issues: err.cause.issues,
|
||||
method: err.method,
|
||||
url: err.url,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (err instanceof BaseError) {
|
||||
return reply.code(err.statusCode ?? 500).send({
|
||||
error: err.name,
|
||||
message: err.message,
|
||||
statusCode: err.statusCode,
|
||||
});
|
||||
}
|
||||
|
||||
return reply.code(500).send({
|
||||
error: 'Internal Server Error',
|
||||
message: err instanceof Error ? err.message : 'An unknown error occurred',
|
||||
statusCode: 500,
|
||||
});
|
||||
});
|
||||
|
||||
app.addHook('onReady', async () => {
|
||||
const warmupService = app.services.get(WarmupService);
|
||||
await warmupService.ensure();
|
||||
});
|
||||
|
||||
await app.register(systemEndpoints, { prefix: '/system' });
|
||||
await app.register(documentEndpoints, { prefix: '/documents' });
|
||||
await app.register(documentFilterEndpoints, { prefix: '/document-filters' });
|
||||
await app.register(documentChunkFilterEndpoints, { prefix: '/document-chunk-filters' });
|
||||
await app.ready();
|
||||
app.swagger();
|
||||
|
||||
return app;
|
||||
};
|
||||
|
||||
export { createApi };
|
||||
Reference in New Issue
Block a user