UNPKG

chanfana

Version:

OpenAPI 3 and 3.1 schema generator and validator for Hono, itty-router and more!

119 lines (99 loc) 3.25 kB
import { z } from "zod"; import { contentJson } from "../contentTypes"; import { InputValidationException, NotFoundException } from "../exceptions"; import { OpenAPIRoute } from "../route"; import { type FilterCondition, type ListFilters, MetaGenerator, type MetaInput, metaSchemaProps, type O, } from "./types"; export class ReadEndpoint<HandleArgs extends Array<object> = Array<object>> extends OpenAPIRoute<HandleArgs> { // @ts-expect-error _meta: MetaInput; get meta() { return MetaGenerator(this._meta); } getSchema() { if ( !this.meta.pathParameters && this.meta.model.primaryKeys.sort().toString() !== this.params.urlParams.sort().toString() ) { throw Error( `Model primaryKeys differ from urlParameters on: ${this.params.route}: ${JSON.stringify(this.meta.model.primaryKeys)} !== ${JSON.stringify(this.params.urlParams)}, fix url parameters or define pathParameters in your Model`, ); } const inputPathParameters = this.meta.pathParameters ?? this.meta.model.primaryKeys; //const queryParameters = this.model.omit((this.primaryKey || []).reduce((a, v) => ({ ...a, [v]: true }), {})); const pathParameters = this.meta.fields.pick( (inputPathParameters || []).reduce((a, v) => ({ ...a, [v]: true }), {}), ); return { request: { //query: queryParameters, params: Object.keys(pathParameters.shape).length ? pathParameters : undefined, ...this.schema?.request, }, responses: { "200": { description: "Returns a single object if found", ...contentJson( z.object({ success: z.boolean(), result: this.meta.model.serializerSchema, }), ), ...this.schema?.responses?.[200], }, ...InputValidationException.schema(), ...NotFoundException.schema(), ...this.schema?.responses, }, ...metaSchemaProps(this._meta), ...this.schema, }; } async getFilters(): Promise<ListFilters> { const data = await this.getValidatedData(); const filters: Array<FilterCondition> = []; for (const part of [data.params, data.query]) { if (part) { for (const [key, value] of Object.entries(part)) { filters.push({ field: key, operator: "EQ", value: value as string, }); } } } return { filters: filters, options: {}, // TODO: make a new type for this }; } async before(filters: ListFilters): Promise<ListFilters> { return filters; } async after(data: O<typeof this._meta>): Promise<O<typeof this._meta>> { return data; } async fetch(_filters: ListFilters): Promise<O<typeof this._meta> | null> { return null; } async handle(..._args: HandleArgs) { let filters = await this.getFilters(); filters = await this.before(filters); let obj = await this.fetch(filters); if (!obj) { throw new NotFoundException(); } obj = await this.after(obj); return { success: true, result: this.meta.model.serializer(obj, { filters: filters.filters, options: filters.options }), }; } }