diff --git a/index.js b/index.js index a74e321..4e8af20 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,16 @@ const express = require('express'); const LimitingMiddleware = require('limiting-middleware'); +const swaggerUi = require('swagger-ui-express'); +const swaggerDocument = require('./swagger.json'); + const { types, randomJoke, randomTen, randomSelect, jokeByType, jokeById, count } = require('./handler'); const app = express(); app.use(new LimitingMiddleware().limitByIp()); - +app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, { + customSiteTitle: "Jokes API" +})); app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); next(); @@ -46,7 +51,7 @@ app.get("/jokes/random/:num", (req, res) => { } } catch (e) { return next(e); - } + } }); app.get('/jokes/ten', (req, res) => { diff --git a/package-lock.json b/package-lock.json index 65a47db..6ae2787 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "license": "ISC", "dependencies": { "express": ">=4.17.2 < 5.0.0", - "limiting-middleware": "^1.3.2" + "limiting-middleware": "^1.3.2", + "swagger-ui-express": "^5.0.1" }, "devDependencies": { "jest": "^26.6.3", @@ -1414,6 +1415,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", + "hasInstallScript": true + }, "node_modules/@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -8012,6 +8019,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swagger-ui-dist": { + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz", + "integrity": "sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==", + "dependencies": { + "@scarf/scarf": "=1.4.0" + } + }, + "node_modules/swagger-ui-express": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz", + "integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==", + "dependencies": { + "swagger-ui-dist": ">=5.0.0" + }, + "engines": { + "node": ">= v0.10.32" + }, + "peerDependencies": { + "express": ">=4.0.0 || >=5.0.0-beta" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -9816,6 +9845,11 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==" + }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -14729,6 +14763,22 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "swagger-ui-dist": { + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz", + "integrity": "sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==", + "requires": { + "@scarf/scarf": "=1.4.0" + } + }, + "swagger-ui-express": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz", + "integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==", + "requires": { + "swagger-ui-dist": ">=5.0.0" + } + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", diff --git a/package.json b/package.json index 98707ea..81c7c5b 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "homepage": "https://github.com/15Dkatz/official_joke_api#readme", "dependencies": { "express": ">=4.17.2 < 5.0.0", - "limiting-middleware": "^1.3.2" + "limiting-middleware": "^1.3.2", + "swagger-ui-express": "^5.0.1" }, "devDependencies": { "jest": "^26.6.3", diff --git a/swagger.json b/swagger.json new file mode 100644 index 0000000..e82085e --- /dev/null +++ b/swagger.json @@ -0,0 +1,315 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Jokes API", + "version": "1.0.0", + "description": "API for fetching jokes (by 15Dkatz/official_joke_api)" + }, + "servers": [ + { + "url": "https://official-joke-api.appspot.com", + "description": "Live server" + }, + { + "url": "http://localhost:3005", + "description": "Local server" + } + ], + "paths": { + "/": { + "get": { + "summary": "Root endpoint", + "description": "Returns a message with available endpoints", + "responses": { + "200": { + "description": "A message with available endpoints", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/ping": { + "get": { + "summary": "Ping endpoint", + "description": "Returns pong", + "responses": { + "200": { + "description": "pong", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/random_joke": { + "get": { + "summary": "Get a random joke", + "responses": { + "200": { + "description": "A random joke", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "punchline": { "type": "string" } + } + } + } + } + } + } + } + }, + "/random_ten": { + "get": { + "summary": "Get ten random jokes", + "responses": { + "200": { + "description": "Ten random jokes", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "punchline": { "type": "string" } + } + } + } + } + } + } + } + } + }, + "/jokes/random": { + "get": { + "summary": "Get a random joke", + "responses": { + "200": { + "description": "A random joke", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "punchline": { "type": "string" } + } + } + } + } + } + } + } + }, + "/jokes/random/{num}": { + "get": { + "summary": "Get a specified number of random jokes", + "parameters": [ + { + "name": "num", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "description": "Number of jokes to retrieve" + } + ], + "responses": { + "200": { + "description": "A specified number of random jokes", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "punchline": { "type": "string" } + } + } + } + } + } + } + } + } + }, + "/jokes/ten": { + "get": { + "summary": "Get ten random jokes", + "responses": { + "200": { + "description": "Ten random jokes", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "punchline": { "type": "string" } + } + } + } + } + } + } + } + } + }, + "/jokes/{type}/random": { + "get": { + "summary": "Get a random joke by type", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Type of joke" + } + ], + "responses": { + "200": { + "description": "A random joke by type", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "punchline": { "type": "string" } + } + } + } + } + } + } + } + }, + "/jokes/{type}/ten": { + "get": { + "summary": "Get ten random jokes by type", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Type of joke" + } + ], + "responses": { + "200": { + "description": "Ten random jokes by type", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "punchline": { "type": "string" } + } + } + } + } + } + } + } + } + }, + "/jokes/{id}": { + "get": { + "summary": "Get a joke by ID", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "description": "ID of the joke" + } + ], + "responses": { + "200": { + "description": "A joke by ID", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "punchline": { "type": "string" } + } + } + } + } + }, + "404": { + "description": "Joke not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { "type": "string" }, + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/types": { + "get": { + "summary": "Get all joke types", + "responses": { + "200": { + "description": "List of joke types", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + \ No newline at end of file