Description
Ola,
I want to make a nice swagger schema view of my api. While the @elysia/swagger plugin gets there half of the way, it seems to struggle with schemas. I've dug through all the examples, but none seem to mix params and responses together, or the examples are outdated. (Like the readme of this repo). I've tried different ways of creating layouts for the schemas, but non of them seem to work properly.
I've got an Elysia route set up like the following:
import { Elysia, t } from "elysia"
import { song } from "../../interfaces";
import { db } from "../..";
export const getSkip = (app: Elysia) => app
.get("/skip/:id", ({ params }) => {
return db.query("SELECT user_id, start, end FROM skip WHERE `song_id`=$songId").all({
$songId: params.id
}) as song[];
}, {
params: t.Object({
id: t.Number({
description: "The ID of the song you want to fetch skips from."
})
}, {
description: "Request body to get all skips belonging to a song."
}),
response: {
200: t.Array(
t.Object({
user_id: t.Number({
description: "The Soundcloud id of the uploader.",
minimum: 0
}),
start: t.Number({
description: "Timestamp where the song skip starts.",
minimum: 0
}),
end: t.Number({
description: "Timestamp where the song skip ends.",
minimum: 0
})
}), {
description: "Returns an array of skip items belonging to the song id."
}
),
},
type: ["arrayBuffer", "application/json"],
description: "Gets all skips of a song.",
})
Then I run the route like this:
new Elysia()
.use(swagger(swaggerDocs)) //Basic dcoumentation options
.group("/skip", app => app
.use(getSkip) //The route from above
)
.listen(port, () => console.log(`Listening on port ${port}...`));
My swagger starts up successfully, but some functionality is broken. I can not inspect the schema, and can not log into my oauth.
I threw the generated swagger schema into insomnia to inspect any errors, it came out with the following:
❌ Elysia generated
{
"openapi": "3.0.3",
"components": {
"schemas": {}
},
"security": [
{
"ApiKeyAuth": [] ❌ <--- Api "security" values must match a scheme defined in the "components.securitySchemes" object
}
],
"servers": [
{
"description": "Local host",
"url": "http://localhost:3001"
}
],
"info": {
"title": "Skipcloud API",
"description": "API used to upload sections of soundcloud songs to skip over.",
"version": "0.0.1",
"contact": {
"name": "@hang_yourself on discord"
}
},
"paths": {
"/skip/{id}": {
"get": {
"parameters": [
{
❌ <--- "0" property must have required property "schema".
"description": "The ID of the song you want to fetch skips from.",
"type": "number",
"in": "path",
"name": "id",
"required": true
}
],
"responses": {
"200": {
"description": "Returns an array of skip items belonging to the song id.",
"items": { ❌ <--- Property "items" is not expected to be here
"type": "object",
"properties": {
"user_id": {
"description": "The Soundcloud id of the uploader.",
"minimum": 0,
"type": "number"
},
"start": {
"description": "Timestamp where the song skip starts.",
"minimum": 0,
"type": "number"
},
"end": {
"description": "Timestamp where the song skip ends.",
"minimum": 0,
"type": "number"
}
},
"required": [
"user_id",
"start",
"end"
]
},
"content": {
"arrayBuffer": {
"schema": {
"type": "array"
}
},
"application/json": {
"schema": {
"type": "array"
}
}
}
}
},
"operationId": "getSkipById"
}
}
}
}
Fixes
✅ Error 1
I have an API key in my header, I have defined my swagger schema as such:
import { ElysiaSwaggerConfig } from "@elysiajs/swagger/src/types";
export default {
documentation: {
components: {
securitySchemes: {
ApiKeyAuth: {
type: "apiKey",
in: "header",
name: "Authorization",
description: "Key used to log into the soundcloud API."
}
},
//... etc
}
} as ElysiaSwaggerConfig;
This however does not show up in the schema. The schema stays empty.
✅ Error 2
The first error seems to be caused by not putting "type: number" in a schema object:
"parameters": [
{
"description": "The ID of the song you want to fetch skips from.",
"schema": {
"type": "number"
},
"in": "path",
"name": "id",
"required": true
}
],
✅ Error 3
This error seems to be caused by the response schema directly being in the 200 object, instead of inside the content objects.
"responses": {
"200": {
"description": "Returns an array of skip items belonging to the song id.",
"content": {
"arrayBuffer": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"user_id": {
"description": "The Soundcloud id of the uploader.",
"minimum": 0,
"type": "number"
},
"start": {
"description": "Timestamp where the song skip starts.",
"minimum": 0,
"type": "number"
},
"end": {
"description": "Timestamp where the song skip ends.",
"minimum": 0,
"type": "number"
}
},
"required": [
"user_id",
"start",
"end"
]
}
}
},
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"user_id": {
"description": "The Soundcloud id of the uploader.",
"minimum": 0,
"type": "number"
},
"start": {
"description": "Timestamp where the song skip starts.",
"minimum": 0,
"type": "number"
},
"end": {
"description": "Timestamp where the song skip ends.",
"minimum": 0,
"type": "number"
}
}
}
}
}
}
}
}
With these manual fixes, I end up with the schema view that I want:
I hope this post clearly outlines the issues I am facing with the swagger plugin. If there is any context missing, please let me know.
Please don't be another stupid oversight by myself🙏