Skip to content

Commit

Permalink
feat(createendpoint): allow to omit the input property (#16)
Browse files Browse the repository at this point in the history
In cases when there's no input, like on GET requests, you can omit the input object and the OAS will
not render it
  • Loading branch information
khaosdoctor authored Mar 30, 2024
1 parent 23eb7cd commit d2851b0
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 16 deletions.
3 changes: 2 additions & 1 deletion src/lib/create-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ function wrapWithRescueAndValidation<T extends Routing>(routing: T) {
Object.entries(route).map(([method, endpoint]) => {
const handlers = Array.isArray(endpoint.handlers) ? endpoint.handlers : [endpoint.handlers]
const rescuedHandlers = handlers.map(rescue)
const finalHandlers = endpoint.input ? [validate(endpoint.input), ...rescuedHandlers] : rescuedHandlers
const wrappedRouteDef = {
...endpoint,
handlers: [validate(endpoint.input), ...rescuedHandlers],
handlers: finalHandlers,
}
return [method, wrappedRouteDef]
}),
Expand Down
22 changes: 7 additions & 15 deletions src/lib/create-endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import {
type ParameterLocation,
type ResponseObject,
} from 'openapi3-ts/oas31'
import { z, type ZodObject, type ZodTypeAny } from 'zod'

const emptySchema = z.object({})
import { type z, type ZodObject, type ZodTypeAny } from 'zod'

export type OneOrMore<T> = T | T[]
export type ValueOf<T> = T[keyof T]
Expand Down Expand Up @@ -44,7 +42,7 @@ export type Endpoint<
ResponseBodies extends ResponseMap = any,
> = OperationObject & {
handlers: OneOrMore<Handler<RequestBody, Params, Query, ResponseBodies>>
input: {
input?: {
body?: ZodObject<any, 'strip', ZodTypeAny, RequestBody, any>
params?: ZodObject<any, 'strip', ZodTypeAny, Params, any>
query?: ZodObject<any, 'strip', ZodTypeAny, Query, any>
Expand All @@ -58,7 +56,7 @@ export type EndpointParams<
Query,
ResponseBodies extends ResponseMap,
> = Partial<OperationObject> & {
input: {
input?: {
body?: ZodObject<any, 'strip', ZodTypeAny, RequestBody, any>
params?: ZodObject<any, 'strip', ZodTypeAny, Params, any>
query?: ZodObject<any, 'strip', ZodTypeAny, Query, any>
Expand Down Expand Up @@ -96,8 +94,8 @@ export function createEndpoint<RequestBody, Params, Query, ResponseBodies extend

const responses = Object.fromEntries(Object.entries(output).map(getResponseFromOutput))

const inputParams: Record<string, unknown> = input.params ? input.params._def.shape() : {}
const inputQuery: Record<string, unknown> = input.query ? input.query._def.shape() : {}
const inputParams: Record<string, unknown> = input?.params ? input.params._def.shape() : {}
const inputQuery: Record<string, unknown> = input?.query ? input.query._def.shape() : {}
const params = [
...Object.entries(inputParams).map(
([key, value]) => ({
Expand All @@ -111,7 +109,7 @@ export function createEndpoint<RequestBody, Params, Query, ResponseBodies extend
in: 'query' as const,
schema: generateSchema(value as ZodTypeAny),
})),
...Object.entries(input.headers ?? {}).map(([key, value]) => ({
...Object.entries(input?.headers ?? {}).map(([key, value]) => ({
name: key,
in: 'header' as ParameterLocation,
schema: { type: 'string' as const },
Expand All @@ -124,13 +122,7 @@ export function createEndpoint<RequestBody, Params, Query, ResponseBodies extend
...openApiParams,
responses,
parameters: params,
requestBody: {
content: {
'application/json': {
schema: generateSchema(input.body ?? emptySchema),
},
},
},
requestBody: input?.body ? { content: { 'application/json': { schema: generateSchema(input.body) } } } : undefined,
handlers,
input,
output,
Expand Down
15 changes: 15 additions & 0 deletions usage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ const dummy = createEndpoint({
},
})

const noInput = createEndpoint({
description: 'This is a dummy endpoint with no input',
output: {
200: {
body: z.object({ ok: z.boolean() }),
},
},
handlers: (_req, res, _next) => {
res.status(200).json({ ok: true })
},
})

const routing: Routing = {
'/users': {
post: createUser,
Expand All @@ -151,6 +163,9 @@ const routing: Routing = {
'/dummy': {
post: dummy,
},
'/no-input': {
post: noInput,
},
}

const openApiInfo: OpenApiInfo = {
Expand Down

0 comments on commit d2851b0

Please sign in to comment.