From 8901b385ad3f12491a42547a5f2aa568987cb0c2 Mon Sep 17 00:00:00 2001 From: wancat Date: Tue, 18 Jul 2023 20:11:05 +0800 Subject: [PATCH] Add swagger --- server/api/swagger.yaml | 462 ++++++++++++++++++++++++++++++++++++++++ server/index.js | 8 + server/package.json | 4 +- yarn.lock | 14 +- 4 files changed, 486 insertions(+), 2 deletions(-) create mode 100644 server/api/swagger.yaml diff --git a/server/api/swagger.yaml b/server/api/swagger.yaml new file mode 100644 index 0000000..977d76d --- /dev/null +++ b/server/api/swagger.yaml @@ -0,0 +1,462 @@ +--- +openapi: 3.0.0 +info: + title: Session API + description: Linux Odyssey API + contact: + email: wancat@wancat.cc + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 +servers: + - url: / +tags: + - name: admins + description: Secured Admin-only calls + - name: developers + description: Operations available to regular developers +paths: + /sessions: + get: + tags: + - signed-in + summary: list existing sessions of current user + responses: + '200': + description: list of existing session + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Session' + security: + - BearerAuth: [] + post: + tags: + - signed-in + summary: create a new session for current user + parameters: + - name: exercise_id + in: query + description: pass the exercise id + required: true + style: form + explode: true + schema: + type: string + responses: + '201': + description: session created + content: + application/json: + schema: + $ref: '#/components/schemas/Session' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/inline_response_400' + security: + - BearerAuth: [] + /sessions/{session_id}: + get: + tags: + - signed-in + summary: get a specific session of current user by ID + parameters: + - name: session_id + in: path + description: ID of the session to retrieve + required: true + style: simple + explode: false + schema: + type: string + format: uuid + responses: + '200': + description: the session + content: + application/json: + schema: + $ref: '#/components/schemas/Session' + '404': + description: cannot find specific session + content: + application/json: + schema: + $ref: '#/components/schemas/inline_response_400' + security: + - BearerAuth: [] + delete: + tags: + - signed-in + summary: delete a specific session by ID + parameters: + - name: session_id + in: path + required: true + style: simple + explode: false + schema: + type: string + format: uuid + responses: + '204': + description: Session successfully deleted + '404': + description: Session not found + content: + application/json: + schema: + $ref: '#/components/schemas/inline_response_404' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/inline_response_401' + security: + - BearerAuth: [] + /inventory: + get: + tags: + - developers + summary: searches inventory + description: | + By passing in the appropriate options, you can search for + available inventory in the system + operationId: searchInventory + parameters: + - name: searchString + in: query + description: pass an optional search string for looking up inventory + required: false + style: form + explode: true + schema: + type: string + - name: skip + in: query + description: number of records to skip for pagination + required: false + style: form + explode: true + schema: + minimum: 0 + type: integer + format: int32 + - name: limit + in: query + description: maximum number of records to return + required: false + style: form + explode: true + schema: + maximum: 50 + minimum: 0 + type: integer + format: int32 + responses: + '200': + description: search results matching criteria + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/InventoryItem' + '400': + description: bad input parameter + post: + tags: + - admins + summary: adds an inventory item + description: Adds an item to the system + operationId: addInventory + requestBody: + description: Inventory item to add + content: + application/json: + schema: + $ref: '#/components/schemas/InventoryItem' + responses: + '201': + description: item created + '400': + description: 'invalid input, object invalid' + '409': + description: an existing item already exists + /register: + post: + summary: Register a new user + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/register_body' + required: true + responses: + '201': + description: User created + content: + application/json: + schema: + $ref: '#/components/schemas/inline_response_201' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/inline_response_400_1' + '409': + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/inline_response_409' + /login: + post: + summary: Log in a user + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/login_body' + required: true + responses: + '200': + description: User logged in + content: + application/json: + schema: + $ref: '#/components/schemas/inline_response_200' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/inline_response_400_2' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/inline_response_401_1' + /profile: + tags: + - signed-in + get: + summary: Get the profile of current logged-in user + responses: + '200': + description: Get user's profile + content: + application/json: + schema: + $ref: '#/components/schemas/User' + security: + - BearerAuth: [] +components: + schemas: + User: + type: object + properties: + id: + type: string + format: uuid + username: + type: string + example: alex + email: + type: string + format: email + Exercise: + type: object + properties: + name: + type: string + introduction: + type: string + Session: + type: object + properties: + id: + type: string + format: uuid + user_id: + type: string + format: uuid + exercise_id: + type: string + format: uuid + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + finished_at: + type: string + format: date-time + terminals: + type: array + items: + type: string + graphs: + $ref: '#/components/schemas/TreeNode' + progress: + type: array + items: + $ref: '#/components/schemas/Progress' + hints: + type: array + items: + $ref: '#/components/schemas/Hint' + TreeNode: + type: object + properties: + name: + type: string + display: + type: boolean + children: + type: array + items: + $ref: '#/components/schemas/TreeNode' + Progress: + type: object + properties: + name: + type: string + finished_at: + type: string + format: date-time + skipped_at: + type: string + format: date-time + Hint: + type: object + properties: + name: + type: string + content: + type: string + source: + type: string + InventoryItem: + required: + - id + - manufacturer + - name + - releaseDate + type: object + properties: + id: + type: string + format: uuid + example: d290f1ee-6c54-4b01-90e6-d701748f0851 + name: + type: string + example: Widget Adapter + releaseDate: + type: string + format: date-time + example: 2016-08-29T09:12:33.001Z + manufacturer: + $ref: '#/components/schemas/Manufacturer' + Manufacturer: + required: + - name + type: object + properties: + name: + type: string + example: ACME Corporation + homePage: + type: string + format: url + example: https://www.acme-corp.com + phone: + type: string + example: 408-867-5309 + inline_response_400: + type: object + properties: + message: + type: string + inline_response_404: + type: object + properties: + message: + type: string + example: Session not found. + inline_response_401: + type: object + properties: + message: + type: string + example: Unauthorized. + register_body: + type: object + properties: + username: + type: string + email: + type: string + password: + type: string + inline_response_201: + type: object + properties: + message: + type: string + example: User created successfully + inline_response_400_1: + type: object + properties: + message: + type: string + example: 'Missing username, email or password' + inline_response_409: + type: object + properties: + message: + type: string + example: User already exists + login_body: + type: object + properties: + username: + type: string + password: + type: string + inline_response_200: + type: object + properties: + message: + type: string + example: Login successful + token: + type: string + description: Access token + inline_response_400_2: + type: object + properties: + message: + type: string + example: Missing username or password + inline_response_401_1: + type: object + properties: + message: + type: string + example: Incorrect username or password + securitySchemes: + BearerAuth: + type: http + scheme: bearer + bearerFormat: JWT diff --git a/server/index.js b/server/index.js index 00ea4e3..115446e 100644 --- a/server/index.js +++ b/server/index.js @@ -1,5 +1,9 @@ +import fs from 'fs' import express from 'express' import http from 'http' +import YAML from 'yaml' +import swaggerUI from 'swagger-ui-express' + import socketServer from './socket.js' const port = 3000 @@ -7,6 +11,10 @@ const app = express() const server = http.createServer(app) socketServer(server) +const file = fs.readFileSync('./api/swagger.yaml', 'utf8') +const swaggerDocument = YAML.parse(file) +app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(swaggerDocument)) + app.get('/', (req, res) => { res.send('Hello World!') }) diff --git a/server/package.json b/server/package.json index f89a8b4..ab91f2d 100644 --- a/server/package.json +++ b/server/package.json @@ -11,7 +11,9 @@ "dockerode": "^3.3.5", "express": "^4.18.2", "socket.io": "^4.7.1", - "socket.io-client": "^4.7.1" + "socket.io-client": "^4.7.1", + "swagger-ui-express": "^5.0.0", + "yaml": "^2.3.1" }, "devDependencies": { "nodemon": "^3.0.1" diff --git a/yarn.lock b/yarn.lock index 952fac6..1bde3b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2719,6 +2719,18 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +swagger-ui-dist@>=5.0.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.1.3.tgz#2f9437b08454a07f87d2672cf28f045fb30b10c7" + integrity sha512-W/vZFeZHG+xTN4yu8LXdaIrcnT4Hbr7qRUILYlMEoIiG6nuTylnEGeRcvL64F2eHRA2Jo/fgCSTU06Qfh0lT3g== + +swagger-ui-express@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-5.0.0.tgz#7a00a18dd909574cb0d628574a299b9ba53d4d49" + integrity sha512-tsU9tODVvhyfkNSvf03E6FAk+z+5cU3lXAzMy6Pv4av2Gt2xA0++fogwC4qo19XuFf6hdxevPuVCSKFuMHJhFA== + dependencies: + swagger-ui-dist ">=5.0.0" + synckit@^0.8.5: version "0.8.5" resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3" @@ -3029,7 +3041,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^2.1.1: +yaml@^2.1.1, yaml@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==