2023-08-19 09:40:55 +08:00
|
|
|
/* eslint-disable node/no-extraneous-import */
|
|
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2023-08-24 16:10:26 +08:00
|
|
|
import type { Hono, Env, ToSchema } from 'hono'
|
2023-08-19 09:40:55 +08:00
|
|
|
import { describe, it, expect, expectTypeOf } from 'vitest'
|
2023-08-19 01:43:36 +08:00
|
|
|
import { OpenAPIHono, createRoute, z } from '../src'
|
|
|
|
|
2023-09-12 07:25:41 +08:00
|
|
|
describe('Constructor', () => {
|
|
|
|
it('Should not require init object', () => {
|
|
|
|
expect(() => new OpenAPIHono()).not.toThrow()
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should accept init object', () => {
|
|
|
|
const getPath = () => ''
|
|
|
|
const app = new OpenAPIHono({getPath})
|
|
|
|
|
|
|
|
expect(app.getPath).toBe(getPath)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2023-08-19 01:43:36 +08:00
|
|
|
describe('Basic - params', () => {
|
|
|
|
const ParamsSchema = z.object({
|
|
|
|
id: z
|
|
|
|
.string()
|
|
|
|
.min(3)
|
|
|
|
.openapi({
|
|
|
|
param: {
|
|
|
|
name: 'id',
|
|
|
|
in: 'path',
|
|
|
|
},
|
|
|
|
example: '1212121',
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
|
|
|
|
const UserSchema = z
|
|
|
|
.object({
|
2023-08-23 10:43:59 +08:00
|
|
|
id: z.string().openapi({
|
|
|
|
example: '123',
|
2023-08-19 01:43:36 +08:00
|
|
|
}),
|
|
|
|
name: z.string().openapi({
|
|
|
|
example: 'John Doe',
|
|
|
|
}),
|
|
|
|
age: z.number().openapi({
|
|
|
|
example: 42,
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
.openapi('User')
|
|
|
|
|
|
|
|
const ErrorSchema = z
|
|
|
|
.object({
|
|
|
|
ok: z.boolean().openapi({
|
|
|
|
example: false,
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
.openapi('Error')
|
|
|
|
|
|
|
|
const route = createRoute({
|
|
|
|
method: 'get',
|
2023-08-23 10:43:59 +08:00
|
|
|
path: '/users/{id}',
|
2023-08-19 01:43:36 +08:00
|
|
|
request: {
|
|
|
|
params: ParamsSchema,
|
|
|
|
},
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
|
|
|
schema: UserSchema,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
description: 'Get the user',
|
|
|
|
},
|
|
|
|
400: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
|
|
|
schema: ErrorSchema,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
description: 'Error!',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const app = new OpenAPIHono()
|
|
|
|
|
|
|
|
app.openapi(
|
|
|
|
route,
|
|
|
|
(c) => {
|
|
|
|
const { id } = c.req.valid('param')
|
|
|
|
return c.jsonT({
|
2023-08-23 10:43:59 +08:00
|
|
|
id,
|
2023-08-19 01:43:36 +08:00
|
|
|
age: 20,
|
|
|
|
name: 'Ultra-man',
|
|
|
|
})
|
|
|
|
},
|
|
|
|
(result, c) => {
|
|
|
|
if (!result.success) {
|
|
|
|
const res = c.jsonT(
|
|
|
|
{
|
|
|
|
ok: false,
|
|
|
|
},
|
|
|
|
400
|
|
|
|
)
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
app.doc('/doc', {
|
|
|
|
openapi: '3.0.0',
|
|
|
|
info: {
|
|
|
|
version: '1.0.0',
|
|
|
|
title: 'My API',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 200 response with correct contents', async () => {
|
|
|
|
const res = await app.request('/users/123')
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(await res.json()).toEqual({
|
2023-08-23 10:43:59 +08:00
|
|
|
id: '123',
|
2023-08-19 01:43:36 +08:00
|
|
|
age: 20,
|
|
|
|
name: 'Ultra-man',
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 400 response with correct contents', async () => {
|
|
|
|
const res = await app.request('/users/1')
|
|
|
|
expect(res.status).toBe(400)
|
|
|
|
expect(await res.json()).toEqual({ ok: false })
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return OpenAPI documents', async () => {
|
|
|
|
const res = await app.request('/doc')
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(await res.json()).toEqual({
|
|
|
|
openapi: '3.0.0',
|
|
|
|
info: { version: '1.0.0', title: 'My API' },
|
|
|
|
components: {
|
|
|
|
schemas: {
|
|
|
|
User: {
|
|
|
|
type: 'object',
|
|
|
|
properties: {
|
2023-08-23 10:43:59 +08:00
|
|
|
id: { type: 'string', example: '123' },
|
2023-08-19 01:43:36 +08:00
|
|
|
name: { type: 'string', example: 'John Doe' },
|
|
|
|
age: { type: 'number', example: 42 },
|
|
|
|
},
|
|
|
|
required: ['id', 'name', 'age'],
|
|
|
|
},
|
|
|
|
Error: {
|
|
|
|
type: 'object',
|
|
|
|
properties: { ok: { type: 'boolean', example: false } },
|
|
|
|
required: ['ok'],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
parameters: {},
|
|
|
|
},
|
|
|
|
paths: {
|
2023-08-23 10:43:59 +08:00
|
|
|
'/users/{id}': {
|
2023-08-19 01:43:36 +08:00
|
|
|
get: {
|
|
|
|
parameters: [
|
|
|
|
{
|
|
|
|
schema: { type: 'string', minLength: 3, example: '1212121' },
|
|
|
|
required: true,
|
|
|
|
name: 'id',
|
|
|
|
in: 'path',
|
|
|
|
},
|
|
|
|
],
|
|
|
|
responses: {
|
|
|
|
'200': {
|
|
|
|
description: 'Get the user',
|
|
|
|
content: { 'application/json': { schema: { $ref: '#/components/schemas/User' } } },
|
|
|
|
},
|
|
|
|
'400': {
|
|
|
|
description: 'Error!',
|
|
|
|
content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('Query', () => {
|
|
|
|
const QuerySchema = z.object({
|
|
|
|
page: z.string().openapi({
|
|
|
|
example: '123',
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
|
2023-08-19 15:07:59 +08:00
|
|
|
const BooksSchema = z
|
2023-08-19 01:43:36 +08:00
|
|
|
.object({
|
2023-08-19 15:07:59 +08:00
|
|
|
titles: z.array(z.string().openapi({})),
|
2023-08-19 01:43:36 +08:00
|
|
|
page: z.number().openapi({}),
|
|
|
|
})
|
|
|
|
.openapi('Post')
|
|
|
|
|
|
|
|
const route = createRoute({
|
|
|
|
method: 'get',
|
|
|
|
path: '/books',
|
|
|
|
request: {
|
|
|
|
query: QuerySchema,
|
|
|
|
},
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
2023-08-19 15:07:59 +08:00
|
|
|
schema: BooksSchema,
|
2023-08-19 01:43:36 +08:00
|
|
|
},
|
|
|
|
},
|
2023-08-19 15:07:59 +08:00
|
|
|
description: 'Get books',
|
2023-08-19 01:43:36 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const app = new OpenAPIHono()
|
|
|
|
|
|
|
|
app.openapi(route, (c) => {
|
|
|
|
const { page } = c.req.valid('query')
|
|
|
|
return c.jsonT({
|
2023-08-19 15:07:59 +08:00
|
|
|
titles: ['Good title'],
|
2023-08-19 01:43:36 +08:00
|
|
|
page: Number(page),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 200 response with correct contents', async () => {
|
|
|
|
const res = await app.request('/books?page=123')
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(await res.json()).toEqual({
|
2023-08-19 15:07:59 +08:00
|
|
|
titles: ['Good title'],
|
2023-08-19 01:43:36 +08:00
|
|
|
page: 123,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 400 response with correct contents', async () => {
|
|
|
|
const res = await app.request('/books')
|
|
|
|
expect(res.status).toBe(400)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2023-08-24 23:55:16 +08:00
|
|
|
describe('Header', () => {
|
|
|
|
const HeaderSchema = z.object({
|
|
|
|
'x-request-id': z.string().uuid(),
|
|
|
|
})
|
|
|
|
|
|
|
|
const PingSchema = z
|
|
|
|
.object({
|
|
|
|
'x-request-id': z.string().uuid(),
|
|
|
|
})
|
|
|
|
.openapi('Post')
|
|
|
|
|
|
|
|
const route = createRoute({
|
|
|
|
method: 'get',
|
|
|
|
path: '/ping',
|
|
|
|
request: {
|
|
|
|
headers: HeaderSchema,
|
|
|
|
},
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
|
|
|
schema: PingSchema,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
description: 'Ping',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const app = new OpenAPIHono()
|
|
|
|
|
|
|
|
app.openapi(route, (c) => {
|
|
|
|
const headerData = c.req.valid('header')
|
|
|
|
const xRequestId = headerData['x-request-id']
|
|
|
|
return c.jsonT({
|
|
|
|
'x-request-id': xRequestId,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 200 response with correct contents', async () => {
|
|
|
|
const res = await app.request('/ping', {
|
|
|
|
headers: {
|
|
|
|
'x-request-id': '6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(await res.json()).toEqual({
|
|
|
|
'x-request-id': '6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b',
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 400 response with correct contents', async () => {
|
|
|
|
const res = await app.request('/ping', {
|
|
|
|
headers: {
|
|
|
|
'x-request-id': 'invalid-strings',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
expect(res.status).toBe(400)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('Cookie', () => {
|
|
|
|
const CookieSchema = z.object({
|
|
|
|
debug: z.enum(['0', '1']),
|
|
|
|
})
|
|
|
|
|
|
|
|
const UserSchema = z
|
|
|
|
.object({
|
|
|
|
name: z.string(),
|
|
|
|
debug: z.enum(['0', '1']),
|
|
|
|
})
|
|
|
|
.openapi('User')
|
|
|
|
|
|
|
|
const route = createRoute({
|
|
|
|
method: 'get',
|
|
|
|
path: '/api/user',
|
|
|
|
request: {
|
|
|
|
cookies: CookieSchema,
|
|
|
|
},
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
|
|
|
schema: UserSchema,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
description: 'Get a user',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const app = new OpenAPIHono()
|
|
|
|
|
|
|
|
app.openapi(route, (c) => {
|
|
|
|
const { debug } = c.req.valid('cookie')
|
|
|
|
return c.jsonT({
|
|
|
|
name: 'foo',
|
|
|
|
debug,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 200 response with correct contents', async () => {
|
|
|
|
const res = await app.request('/api/user', {
|
|
|
|
headers: {
|
|
|
|
Cookie: 'debug=1',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(await res.json()).toEqual({
|
|
|
|
name: 'foo',
|
|
|
|
debug: '1',
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 400 response with correct contents', async () => {
|
|
|
|
const res = await app.request('/api/user', {
|
|
|
|
headers: {
|
|
|
|
Cookie: 'debug=2',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
expect(res.status).toBe(400)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2023-08-19 01:43:36 +08:00
|
|
|
describe('JSON', () => {
|
|
|
|
const RequestSchema = z.object({
|
|
|
|
id: z.number().openapi({}),
|
|
|
|
title: z.string().openapi({}),
|
|
|
|
})
|
|
|
|
|
2023-08-19 15:07:59 +08:00
|
|
|
const PostSchema = z
|
2023-08-19 01:43:36 +08:00
|
|
|
.object({
|
|
|
|
id: z.number().openapi({}),
|
|
|
|
title: z.string().openapi({}),
|
|
|
|
})
|
|
|
|
.openapi('Post')
|
|
|
|
|
|
|
|
const route = createRoute({
|
|
|
|
method: 'post',
|
|
|
|
path: '/posts',
|
|
|
|
request: {
|
|
|
|
body: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
|
|
|
schema: RequestSchema,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
2023-08-19 15:07:59 +08:00
|
|
|
schema: PostSchema,
|
2023-08-19 01:43:36 +08:00
|
|
|
},
|
|
|
|
},
|
2023-08-19 15:07:59 +08:00
|
|
|
description: 'Post a post',
|
2023-08-19 01:43:36 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const app = new OpenAPIHono()
|
|
|
|
|
|
|
|
app.openapi(route, (c) => {
|
|
|
|
const { id, title } = c.req.valid('json')
|
|
|
|
return c.jsonT({
|
|
|
|
id,
|
|
|
|
title,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 200 response with correct contents', async () => {
|
|
|
|
const req = new Request('http://localhost/posts', {
|
|
|
|
method: 'POST',
|
|
|
|
body: JSON.stringify({
|
|
|
|
id: 123,
|
|
|
|
title: 'Good title',
|
|
|
|
}),
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const res = await app.request(req)
|
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(await res.json()).toEqual({
|
|
|
|
id: 123,
|
|
|
|
title: 'Good title',
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 400 response with correct contents', async () => {
|
|
|
|
const req = new Request('http://localhost/posts', {
|
|
|
|
method: 'POST',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
},
|
2023-08-19 15:07:59 +08:00
|
|
|
body: JSON.stringify({}),
|
2023-08-19 01:43:36 +08:00
|
|
|
})
|
|
|
|
const res = await app.request(req)
|
|
|
|
expect(res.status).toBe(400)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('Form', () => {
|
|
|
|
const RequestSchema = z.object({
|
|
|
|
id: z.string().openapi({}),
|
|
|
|
title: z.string().openapi({}),
|
|
|
|
})
|
|
|
|
|
2023-08-19 15:07:59 +08:00
|
|
|
const PostSchema = z
|
2023-08-19 01:43:36 +08:00
|
|
|
.object({
|
|
|
|
id: z.number().openapi({}),
|
|
|
|
title: z.string().openapi({}),
|
|
|
|
})
|
|
|
|
.openapi('Post')
|
|
|
|
|
|
|
|
const route = createRoute({
|
|
|
|
method: 'post',
|
|
|
|
path: '/posts',
|
|
|
|
request: {
|
|
|
|
body: {
|
|
|
|
content: {
|
|
|
|
'application/x-www-form-urlencoded': {
|
|
|
|
schema: RequestSchema,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
2023-08-19 15:07:59 +08:00
|
|
|
schema: PostSchema,
|
2023-08-19 01:43:36 +08:00
|
|
|
},
|
|
|
|
},
|
2023-08-19 15:07:59 +08:00
|
|
|
description: 'Post a post',
|
2023-08-19 01:43:36 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const app = new OpenAPIHono()
|
|
|
|
|
|
|
|
app.openapi(route, (c) => {
|
|
|
|
const { id, title } = c.req.valid('form')
|
|
|
|
return c.jsonT({
|
|
|
|
id: Number(id),
|
|
|
|
title,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 200 response with correct contents', async () => {
|
|
|
|
const searchParams = new URLSearchParams()
|
|
|
|
searchParams.append('id', '123')
|
|
|
|
searchParams.append('title', 'Good title')
|
|
|
|
const req = new Request('http://localhost/posts', {
|
|
|
|
method: 'POST',
|
|
|
|
body: searchParams,
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const res = await app.request(req)
|
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(await res.json()).toEqual({
|
|
|
|
id: 123,
|
|
|
|
title: 'Good title',
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 400 response with correct contents', async () => {
|
|
|
|
const req = new Request('http://localhost/posts', {
|
|
|
|
method: 'POST',
|
|
|
|
})
|
|
|
|
const res = await app.request(req)
|
|
|
|
expect(res.status).toBe(400)
|
|
|
|
})
|
|
|
|
})
|
2023-08-19 09:40:55 +08:00
|
|
|
|
|
|
|
describe('Types', () => {
|
|
|
|
const RequestSchema = z.object({
|
|
|
|
id: z.number().openapi({}),
|
|
|
|
title: z.string().openapi({}),
|
|
|
|
})
|
|
|
|
|
2023-08-19 15:07:59 +08:00
|
|
|
const PostSchema = z
|
2023-08-19 09:40:55 +08:00
|
|
|
.object({
|
|
|
|
id: z.number().openapi({}),
|
|
|
|
message: z.string().openapi({}),
|
|
|
|
})
|
|
|
|
.openapi('Post')
|
|
|
|
|
|
|
|
const route = createRoute({
|
|
|
|
method: 'post',
|
|
|
|
path: '/posts',
|
|
|
|
request: {
|
|
|
|
body: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
|
|
|
schema: RequestSchema,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
2023-08-19 15:07:59 +08:00
|
|
|
schema: PostSchema,
|
2023-08-19 09:40:55 +08:00
|
|
|
},
|
|
|
|
},
|
2023-08-19 15:07:59 +08:00
|
|
|
description: 'Post a post',
|
2023-08-19 09:40:55 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const app = new OpenAPIHono()
|
|
|
|
|
|
|
|
const appRoutes = app.openapi(route, (c) => {
|
|
|
|
const data = c.req.valid('json')
|
|
|
|
return c.jsonT({
|
|
|
|
id: data.id,
|
|
|
|
message: 'Success',
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return correct types', () => {
|
|
|
|
type H = Hono<
|
|
|
|
Env,
|
2023-08-24 16:10:26 +08:00
|
|
|
ToSchema<
|
|
|
|
'post',
|
|
|
|
'/posts',
|
|
|
|
{
|
|
|
|
json: {
|
|
|
|
title: string
|
|
|
|
id: number
|
2023-08-19 09:40:55 +08:00
|
|
|
}
|
2023-08-24 16:10:26 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
id: number
|
|
|
|
message: string
|
2023-08-19 09:40:55 +08:00
|
|
|
}
|
2023-08-24 16:10:26 +08:00
|
|
|
>,
|
2023-08-19 09:40:55 +08:00
|
|
|
'/'
|
|
|
|
>
|
|
|
|
expectTypeOf(appRoutes).toMatchTypeOf<H>
|
|
|
|
})
|
|
|
|
})
|
2023-09-11 10:44:47 +08:00
|
|
|
|
2023-09-12 07:25:41 +08:00
|
|
|
describe('Routers', () => {
|
|
|
|
const RequestSchema = z.object({
|
|
|
|
id: z.number().openapi({}),
|
|
|
|
})
|
|
|
|
|
|
|
|
const PostSchema = z
|
|
|
|
.object({
|
|
|
|
id: z.number().openapi({}),
|
|
|
|
})
|
|
|
|
.openapi('Post')
|
|
|
|
|
|
|
|
const route = createRoute({
|
|
|
|
method: 'post',
|
|
|
|
path: '/posts',
|
|
|
|
request: {
|
|
|
|
body: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
|
|
|
schema: RequestSchema,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
|
|
|
schema: PostSchema,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
description: 'Post a post',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
it('Should include definitions from nested routers', () => {
|
|
|
|
const router = new OpenAPIHono().openapi(route, (ctx) => {
|
|
|
|
return ctx.jsonT({id: 123})
|
|
|
|
})
|
|
|
|
|
|
|
|
router.openAPIRegistry.register('Id', z.number())
|
|
|
|
|
|
|
|
router.openAPIRegistry.registerParameter('Key', z.number().openapi({
|
|
|
|
param: {in: 'path'}
|
|
|
|
}))
|
|
|
|
|
|
|
|
router.openAPIRegistry.registerWebhook({
|
|
|
|
method: 'post',
|
|
|
|
path: '/postback',
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
description: 'Receives a post back'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
const app = new OpenAPIHono().route('/api', router)
|
|
|
|
const json = app.getOpenAPI31Document({
|
|
|
|
openapi: '3.1.0',
|
|
|
|
info: {
|
|
|
|
title: 'My API',
|
|
|
|
version: '1.0.0',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
expect(json.components?.schemas).toHaveProperty('Id')
|
|
|
|
expect(json.components?.schemas).toHaveProperty('Post')
|
|
|
|
expect(json.components?.parameters).toHaveProperty('Key')
|
|
|
|
expect(json.paths).toHaveProperty('/api/posts')
|
|
|
|
expect(json.webhooks).toHaveProperty('/api/postback')
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2023-09-11 10:44:47 +08:00
|
|
|
describe('Multi params', () => {
|
|
|
|
const ParamsSchema = z.object({
|
|
|
|
id: z.string(),
|
|
|
|
tagName: z.string(),
|
|
|
|
})
|
|
|
|
|
|
|
|
const route = createRoute({
|
|
|
|
method: 'get',
|
|
|
|
path: '/users/{id}/tags/{tagName}',
|
|
|
|
request: {
|
|
|
|
params: ParamsSchema,
|
|
|
|
},
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
// eslint-disable-next-line quotes
|
|
|
|
description: "Get the user's tag",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const app = new OpenAPIHono()
|
|
|
|
|
|
|
|
app.openapi(route, (c) => {
|
|
|
|
const { id, tagName } = c.req.valid('param')
|
|
|
|
return c.jsonT({
|
|
|
|
id,
|
|
|
|
tagName,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return 200 response with correct contents', async () => {
|
|
|
|
const res = await app.request('/users/123/tags/baseball')
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(await res.json()).toEqual({
|
|
|
|
id: '123',
|
|
|
|
tagName: 'baseball',
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|