Skip to content

Commit

Permalink
feat: Use TypeBox for Fastify schema definitions
Browse files Browse the repository at this point in the history
Switched to using TypeBox due to TS errors when using JsonSchema.
TypeBox can also be used for defining Mongoose types to reduce duplication.
  • Loading branch information
jrassa committed Dec 9, 2024
1 parent 492892c commit 0d44c88
Show file tree
Hide file tree
Showing 44 changed files with 1,337 additions and 1,228 deletions.
72 changes: 24 additions & 48 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@
"@fastify/session": "^11.0.1",
"@fastify/swagger": "^9.2.0",
"@fastify/swagger-ui": "^5.1.0",
"@fastify/type-provider-json-schema-to-ts": "^4.0.1",
"@fastify/type-provider-typebox": "^5.0.1",
"@sinclair/typebox": "^0.33.22",
"agenda": "^4.3.0",
"config": "^3.3.11",
"connect-mongo": "^5.1.0",
Expand Down
83 changes: 38 additions & 45 deletions src/app/core/access-checker/access-checker.controller.ts
Original file line number Diff line number Diff line change
@@ -1,82 +1,75 @@
import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts';
import { Type, TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
import { FastifyInstance } from 'fastify';

import accessCheckerService from './access-checker.service';
import cacheEntryService from './cache/cache-entry.service';
import { PagingQueryStringSchema, SearchBodySchema } from '../core.schemas';
import { PagingQueryStringType, SearchBodyType } from '../core.types';
import { requireAdminAccess, requireLogin } from '../user/auth/auth.hooks';

const KeyParamsType = Type.Object({
key: Type.String()
});

export default function (_fastify: FastifyInstance) {
const fastify = _fastify.withTypeProvider<JsonSchemaToTsProvider>();
const fastify = _fastify.withTypeProvider<TypeBoxTypeProvider>();

fastify.route({
method: 'POST',
url: '/access-checker/entry/:key',
url: '/access-checker/entries/match',
schema: {
description: 'Trigger cache entry refresh',
description: 'Search cache entries',
tags: ['Access Checker'],
params: {
type: 'object',
properties: {
key: { type: 'string' }
},
required: ['key']
}
body: SearchBodyType,
querystring: PagingQueryStringType
},
preValidation: requireAdminAccess,
handler: async function (req, reply) {
await accessCheckerService.refreshEntry(req.params.key);
return reply.send();
const results = await cacheEntryService.search(
req.query,
req.body.s,
req.body.q
);

// Create the return copy of the messages
const mappedResults = {
pageNumber: results.pageNumber,
pageSize: results.pageSize,
totalPages: results.totalPages,
totalSize: results.totalSize,
elements: results.elements.map((element) => element.fullCopy())
};

return reply.send(mappedResults);
}
});

fastify.route({
method: 'DELETE',
method: 'POST',
url: '/access-checker/entry/:key',
schema: {
description: 'Delete cache entry',
description: 'Trigger cache entry refresh',
tags: ['Access Checker'],
params: {
type: 'object',
properties: {
key: { type: 'string' }
},
required: ['key']
}
params: KeyParamsType
},
preValidation: requireAdminAccess,
handler: async function (req, reply) {
await cacheEntryService.delete(req.params.key);
await accessCheckerService.refreshEntry(req.params.key);
return reply.send();
}
});

fastify.route({
method: 'POST',
url: '/access-checker/entries/match',
method: 'DELETE',
url: '/access-checker/entry/:key',
schema: {
description: 'Search cache entries',
description: 'Delete cache entry',
tags: ['Access Checker'],
body: SearchBodySchema,
querystring: PagingQueryStringSchema
params: KeyParamsType
},
preValidation: requireAdminAccess,
handler: async function (req, reply) {
const results = await cacheEntryService.search(
req.query,
req.body.s,
req.body.q
);

// Create the return copy of the messages
const mappedResults = {
pageNumber: results.pageNumber,
pageSize: results.pageSize,
totalPages: results.totalPages,
totalSize: results.totalSize,
elements: results.elements.map((element) => element.fullCopy())
};

return reply.send(mappedResults);
await cacheEntryService.delete(req.params.key);
return reply.send();
}
});

Expand Down
20 changes: 12 additions & 8 deletions src/app/core/access-checker/cache/cache-entry.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Schema, model, HydratedDocument, Model, Types } from 'mongoose';
import { Static, Type } from '@fastify/type-provider-typebox';
import { Schema, model, HydratedDocument, Model } from 'mongoose';

import {
ContainsSearchable,
Expand All @@ -9,14 +10,17 @@ import {
paginatePlugin,
Paginateable
} from '../../../common/mongoose/paginate.plugin';
import { DateTimeType, ObjectIdType } from '../../core.types';

export const CacheEntryType = Type.Object({
_id: ObjectIdType,
key: Type.String(),
ts: DateTimeType,
value: Type.Record(Type.String(), Type.Unknown()),
valueString: Type.String()
});

export interface ICacheEntry {
_id: Types.ObjectId;
key: string;
ts: Date;
value: Record<string, unknown>;
valueString: string;
}
export type ICacheEntry = Static<typeof CacheEntryType>;

export interface ICacheEntryMethods {
fullCopy(): Record<string, unknown>;
Expand Down
Loading

0 comments on commit 0d44c88

Please sign in to comment.