diff --git a/CHANGELOG.md b/CHANGELOG.md index d941e85..2105048 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 0.3.0-beta.0 - 25 Feb 2023 +Improvement: +- Support Elysia >= 0.3.0-beta.0 + +Breaking Change: +- Update from OpenAPI 2.x to OpenAPI 3.0.3 +- `swagger.swagger` is renamed to `swagger.documentation` + # 0.1.1 - 8 Jan 2023 Bug fix: - Infers path type diff --git a/bun.lockb b/bun.lockb index 7841c4c..74e68bc 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/example/index.ts b/example/index.ts index 2f71ada..1839398 100644 --- a/example/index.ts +++ b/example/index.ts @@ -1,8 +1,23 @@ -import { Elysia, t } from 'elysia' +import { Elysia, t, SCHEMA } from 'elysia' import swagger from '../src/index' const app = new Elysia() - .use(swagger()) + .use( + swagger({ + documentation: { + info: { + title: 'Elysia', + version: '0.3.0' + }, + tags: [ + { + name: 'Test', + description: 'Hello' + } + ] + } + }) + ) .setModel({ sign: t.Object( { @@ -10,13 +25,12 @@ const app = new Elysia() password: t.String() }, { - title: 'Sign Model', description: 'Models for handling authentication' } ), number: t.Number() }) - .get('/', () => 'hi', { + .get('/', ({ set }) => 'hi', { schema: { detail: { summary: 'Ping Pong', @@ -28,13 +42,25 @@ const app = new Elysia() .get('/unpath/:id', ({ params: { id } }) => id, { schema: { params: t.Object({ - id: t.String({ description: 'ID to get' }) + id: t.String({ + description: 'Extract value from path parameter' + }) }), detail: { deprecated: true } } }) + .post('/json', ({ body }) => body, { + schema: { + contentType: 'application/json', + body: 'sign', + response: 'sign', + detail: { + summary: 'Using reference model' + } + } + }) .post( '/json/:id', ({ body, params: { id }, query: { name } }) => ({ @@ -42,20 +68,24 @@ const app = new Elysia() id }), { + transform({ params }) { + params.id = +params.id + }, schema: { body: 'sign', + params: t.Object({ + id: t.Number() + }), response: { 200: t.Object( { - username: t.String({ - title: 'A' - }), - password: t.String(), - id: t.String() + id: t.Number(), + username: t.String(), + password: t.String() }, { - description: 'A', - title: 'A' + title: 'User', + description: "Contains user's confidential metadata" } ), 400: t.Object({ @@ -63,16 +93,34 @@ const app = new Elysia() }) }, detail: { - summary: 'A' + summary: 'Transform path parameter' } } } ) - .get('/unpath/:id/:name', ({ params: { id } }) => id) - .post('/json', ({ body }) => body, { + .post('/file', ({ body: { file } }) => file, { schema: { - body: 'sign', - response: 'sign' + contentType: 'multipart/form-data', + detail: { + summary: 'Upload file demo', + description: + 'An example usage of using Elysia 0.3 to handle file upload' + }, + body: t.Object({ + file: t.File() + }), + response: t.File() + } + }) + .post('/files', ({ body: { files } }) => files[0], { + schema: { + body: t.Object({ + files: t.Files({ + type: 'image', + maxSize: '5m' + }) + }), + response: t.File() } }) .listen(8080) diff --git a/package.json b/package.json index 59ca4a5..651bfb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elysiajs/swagger", - "version": "0.2.0", + "version": "0.3.0-beta.0", "description": "Plugin for Elysia to auto-generate Swagger page", "author": { "name": "saltyAom", @@ -33,18 +33,18 @@ "release": "npm run build && npm run test && npm publish --access public" }, "peerDependencies": { - "elysia": ">= 0.2.0" + "elysia": ">= 0.3.0-beta.0" }, "devDependencies": { "@types/node": "^18.11.7", "@types/swagger-ui-dist": "^3.30.1", - "bun-types": "^0.5.0", + "bun-types": "^0.5.7", "eslint": "^8.26.0", - "elysia": "^0.2.0", - "typescript": "^4.9.3" + "elysia": "^0.3.0-beta.1", + "typescript": "^4.9.4" }, "dependencies": { "@elysiajs/static": "0.2.0", - "swagger-ui-dist": "^4.15.5" + "swagger-ui-dist": "^4.16.0" } } diff --git a/src/index.ts b/src/index.ts index a68622c..adbd837 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,20 +1,13 @@ import { type Elysia, SCHEMA, DEFS } from 'elysia' -import { getAbsoluteFSPath } from 'swagger-ui-dist' - import { staticPlugin } from '@elysiajs/static' -import type { OpenAPIV2 } from 'openapi-types' +import { getAbsoluteFSPath } from 'swagger-ui-dist' + +import type { OpenAPIV3 } from 'openapi-types' import { filterPaths, formatSwagger } from './utils' import type { ElysiaSwaggerConfig } from './types' -const defaultConfig: Partial = { - swagger: '2.0', - schemes: ['http', 'https'], - consumes: ['application/json', 'text/plain'], - produces: ['application/json', 'text/plain'] -} - /** * Plugin for [elysia](https://github.com/elysiajs/elysia) that auto-generate Swagger page. * @@ -23,12 +16,12 @@ const defaultConfig: Partial = { export const swagger = ( { - swagger = {}, + documentation = {}, excludeStaticFile = true, path = '/swagger' as Path, exclude = [] }: ElysiaSwaggerConfig = { - swagger: {}, + documentation: {}, excludeStaticFile: true, path: '/swagger' as Path, exclude: [] @@ -36,8 +29,58 @@ export const swagger = ) => (app: Elysia) => { app.get(path, (context) => { - context.set.redirect = `${path}/static/index.html` + return new Response( + ` + + + Redirecting... + + + + + + If you're not being redirected, use this + + link + + +`, + { + status: 302, + headers: { + 'content-type': 'text/html; charset=utf8', + Location: `${path}/static/index.html` + } + } + ) }) + .get( + `${path}/json`, + (content) => + ({ + openapi: '3.0.3', + ...{ + ...documentation, + info: { + title: 'Elysia Documentation', + description: 'Developement documentation', + version: '0.0.0', + ...documentation.info + } + }, + paths: filterPaths(content[SCHEMA], { + excludeStaticFile, + exclude: Array.isArray(exclude) + ? exclude + : [exclude] + }), + components: { + schemas: content[DEFS] + } + } satisfies OpenAPIV3.Document) + ) .get( `${path}/static/swagger-initializer.js`, () => @@ -47,23 +90,6 @@ export const swagger = } }) ) - .get(`${path}/json`, ({ store }) => ({ - ...{ - ...defaultConfig, - ...swagger, - info: { - title: 'Elysia Documentation', - description: 'Developement documentation', - version: '0.0.0', - ...swagger.info - } - }, - paths: filterPaths(store[SCHEMA], { - excludeStaticFile, - exclude: Array.isArray(exclude) ? exclude : [exclude] - }), - definitions: store[DEFS] - })) .use( staticPlugin({ prefix: `${path}/static`, diff --git a/src/types.ts b/src/types.ts index 9849894..1c0108a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import type { OpenAPIV2 } from "openapi-types" +import type { OpenAPIV3 } from 'openapi-types' export interface ElysiaSwaggerConfig { /** @@ -6,7 +6,11 @@ export interface ElysiaSwaggerConfig { * * @see https://swagger.io/specification/v2/ */ - swagger?: Partial + documentation?: Omit< + Partial, + | 'x-express-openapi-additional-middleware' + | 'x-express-openapi-validation-strict' + > /** * Determine if Swagger should exclude static files. * diff --git a/test/index.test.ts b/test/index.test.ts index b0165aa..ccd13ef 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -3,7 +3,7 @@ import { swagger } from '../src' import { describe, expect, it } from 'bun:test' -const req = (path: string) => new Request(path) +const req = (path: string) => new Request(`http://localhost${path}`) describe('Swagger', () => { it('redirect to Swagger page', async () => {