update
This commit is contained in:
45
packages/server/src/api/api.ts
Normal file
45
packages/server/src/api/api.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import fastify from 'fastify';
|
||||
import fastifySwagger from '@fastify/swagger';
|
||||
import fastifyApiReference from '@scalar/fastify-api-reference';
|
||||
import { jsonSchemaTransform, serializerCompiler, validatorCompiler } from 'fastify-type-provider-zod';
|
||||
import type { Services } from '@morten-olsen/fluxcurrent-core/utils/services.ts';
|
||||
import { FastifySSEPlugin } from 'fastify-sse-v2';
|
||||
|
||||
import { searchEndpoint } from './endpoints/endpoints.search.ts';
|
||||
import { documentsEndpoint } from './endpoints/endpoints.documents.ts';
|
||||
|
||||
type CreateApiOptions = {
|
||||
services: Services;
|
||||
};
|
||||
|
||||
const createApi = async (options: CreateApiOptions) => {
|
||||
const app = fastify();
|
||||
app.setValidatorCompiler(validatorCompiler);
|
||||
app.setSerializerCompiler(serializerCompiler);
|
||||
|
||||
app.register(fastifySwagger, {
|
||||
openapi: {
|
||||
info: {
|
||||
title: 'SampleApi',
|
||||
description: 'Sample backend service',
|
||||
version: '1.0.0',
|
||||
},
|
||||
servers: [],
|
||||
},
|
||||
transform: jsonSchemaTransform,
|
||||
});
|
||||
|
||||
await app.register(fastifyApiReference, {
|
||||
routePrefix: '/docs',
|
||||
});
|
||||
|
||||
await app.register(FastifySSEPlugin);
|
||||
|
||||
await app.register(searchEndpoint, { services: options.services, prefix: '/search' });
|
||||
await app.register(documentsEndpoint, { services: options.services, prefix: '/documents' });
|
||||
|
||||
await app.ready();
|
||||
return app;
|
||||
};
|
||||
|
||||
export { createApi };
|
||||
24
packages/server/src/api/endpoints/endpoints.documents.ts
Normal file
24
packages/server/src/api/endpoints/endpoints.documents.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { FastifyPluginAsyncZod } from 'fastify-type-provider-zod';
|
||||
import { z } from 'zod/v4';
|
||||
import type { Services } from '@morten-olsen/fluxcurrent-core/utils/services.ts';
|
||||
import { DocumentsService } from '@morten-olsen/fluxcurrent-core/services/documents/documents.ts';
|
||||
import { documentUpsertSchema } from '@morten-olsen/fluxcurrent-core/services/documents/documents.schemas.ts';
|
||||
|
||||
const documentsEndpoint: FastifyPluginAsyncZod<{ services: Services }> = async (fastify, { services }) => {
|
||||
fastify.route({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
schema: {
|
||||
body: z.object({
|
||||
document: documentUpsertSchema,
|
||||
}),
|
||||
},
|
||||
handler: async (req, res) => {
|
||||
const documentsService = services.get(DocumentsService);
|
||||
const documents = await documentsService.upsert(req.body.document);
|
||||
res.send(documents);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export { documentsEndpoint };
|
||||
62
packages/server/src/api/endpoints/endpoints.search.ts
Normal file
62
packages/server/src/api/endpoints/endpoints.search.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import type { FastifyPluginAsyncZod } from 'fastify-type-provider-zod';
|
||||
import { z } from 'zod/v4';
|
||||
import type { Services } from '@morten-olsen/fluxcurrent-core/utils/services.ts';
|
||||
import { parseDSL } from '@morten-olsen/fluxcurrent-core/services/documents/documents.dsl.ts';
|
||||
import { DocumentsService } from '@morten-olsen/fluxcurrent-core/services/documents/documents.ts';
|
||||
import {
|
||||
documentSchema,
|
||||
type DocumentUpsertEvent,
|
||||
} from '@morten-olsen/fluxcurrent-core/services/documents/documents.schemas.ts';
|
||||
import { filterDocument } from '@morten-olsen/fluxcurrent-core/services/documents/documents.filter.ts';
|
||||
|
||||
const searchEndpoint: FastifyPluginAsyncZod<{ services: Services }> = async (fastify, { services }) => {
|
||||
fastify.route({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
schema: {
|
||||
body: z.object({
|
||||
query: z.string().optional(),
|
||||
}),
|
||||
response: {
|
||||
200: z.array(documentSchema),
|
||||
},
|
||||
},
|
||||
handler: async (req, res) => {
|
||||
const query = req.body.query ? parseDSL(req.body.query) : {};
|
||||
const documentsService = services.get(DocumentsService);
|
||||
const documents = await documentsService.search(query);
|
||||
res.send(documents);
|
||||
},
|
||||
});
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/stream',
|
||||
schema: {
|
||||
querystring: z.object({
|
||||
query: z.string().optional(),
|
||||
}),
|
||||
},
|
||||
handler: async (req, res) => {
|
||||
const query = req.query.query ? parseDSL(req.query.query) : {};
|
||||
const documentsService = services.get(DocumentsService);
|
||||
res.sse({ event: 'init' });
|
||||
const documents = await documentsService.search(query);
|
||||
for (const document of documents) {
|
||||
res.sse({ event: 'upsert', data: JSON.stringify(document) });
|
||||
}
|
||||
const listener = (event: DocumentUpsertEvent) => {
|
||||
if (query.meta && !filterDocument(query.meta, event.document)) {
|
||||
return;
|
||||
}
|
||||
res.sse({ event: 'upsert', data: JSON.stringify(event) });
|
||||
};
|
||||
documentsService.on('upsert', listener);
|
||||
req.socket.on('close', () => {
|
||||
documentsService.off('upsert', listener);
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export { searchEndpoint };
|
||||
Reference in New Issue
Block a user