feat: Serve swagger doc ui on root endpoint (#34)

* feat: serve swagger ui on root endpoint (#33)

* feat: serve swagger ui on root endpoint

* remove home controller

* feat(swagger): Customize root page title and favicon
This commit is contained in:
r1oga
2023-02-01 22:31:45 +00:00
committed by GitHub
parent 86e332bc6d
commit 166e5fe8a0
7 changed files with 282 additions and 71 deletions

View File

@@ -29,6 +29,7 @@
"@types/jest": "^29.2.3",
"@types/node": "^18.11.18",
"@types/supertest": "^2.0.12",
"@types/swagger-ui-express": "^4.1.3",
"@types/yargs": "^17.0.19",
"barrelsby": "^2.5.1",
"concurrently": "^7.6.0",
@@ -70,6 +71,8 @@
"@octokit/graphql": "^5.0.5",
"@octokit/plugin-paginate-graphql": "^2.0.1",
"@prisma/client": "^4.9.0",
"@types/cors": "^2.8.13",
"cors": "^2.8.5",
"cross-fetch": "^3.1.5",
"express": "^4.18.2",
"express-async-errors": "^3.1.1",
@@ -77,6 +80,7 @@
"is-docker": "^3.0.0",
"module-alias": "^2.2.2",
"reflect-metadata": "^0.1.13",
"swagger-ui-express": "^4.6.0",
"tslib": "^2.5.0",
"typedi": "^0.10.0"
}

49
pnpm-lock.yaml generated
View File

@@ -11,13 +11,16 @@ specifiers:
'@prisma/client': ^4.9.0
'@r1oga/eslint-config': ^1.1.6
'@r1oga/prettier-config': ^1.1.8
'@types/cors': ^2.8.13
'@types/express': ^4.17.15
'@types/jest': ^29.2.3
'@types/node': ^18.11.18
'@types/supertest': ^2.0.12
'@types/swagger-ui-express': ^4.1.3
'@types/yargs': ^17.0.19
barrelsby: ^2.5.1
concurrently: ^7.6.0
cors: ^2.8.5
cross-fetch: ^3.1.5
dotenv-cli: ^7.0.0
express: ^4.18.2
@@ -41,6 +44,7 @@ specifiers:
prisma: ^4.9.0
reflect-metadata: ^0.1.13
supertest: ^6.3.3
swagger-ui-express: ^4.6.0
ts-jest: ^29.0.3
ts-node-dev: ^2.0.0
tsconfig-paths: ^4.1.0
@@ -54,6 +58,8 @@ dependencies:
'@octokit/graphql': 5.0.5
'@octokit/plugin-paginate-graphql': 2.0.1_@octokit+core@4.2.0
'@prisma/client': 4.9.0_prisma@4.9.0
'@types/cors': 2.8.13
cors: 2.8.5
cross-fetch: 3.1.5
express: 4.18.2
express-async-errors: 3.1.1_express@4.18.2
@@ -61,6 +67,7 @@ dependencies:
is-docker: 3.0.0
module-alias: 2.2.2
reflect-metadata: 0.1.13
swagger-ui-express: 4.6.0_express@4.18.2
tslib: 2.5.0
typedi: 0.10.0
@@ -75,6 +82,7 @@ devDependencies:
'@types/jest': 29.2.3
'@types/node': 18.11.18
'@types/supertest': 2.0.12
'@types/swagger-ui-express': 4.1.3
'@types/yargs': 17.0.19
barrelsby: 2.5.1
concurrently: 7.6.0
@@ -1146,6 +1154,12 @@ packages:
resolution: {integrity: sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==}
dev: true
/@types/cors/2.8.13:
resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==}
dependencies:
'@types/node': 18.11.18
dev: false
/@types/express-serve-static-core/4.17.32:
resolution: {integrity: sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==}
dependencies:
@@ -1212,7 +1226,6 @@ packages:
/@types/node/18.11.18:
resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==}
dev: true
/@types/parse-json/4.0.0:
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
@@ -1266,6 +1279,13 @@ packages:
'@types/superagent': 4.1.16
dev: true
/@types/swagger-ui-express/4.1.3:
resolution: {integrity: sha512-jqCjGU/tGEaqIplPy3WyQg+Nrp6y80DCFnDEAvVKWkJyv0VivSSDCChkppHRHAablvInZe6pijDFMnavtN0vqA==}
dependencies:
'@types/express': 4.17.15
'@types/serve-static': 1.15.0
dev: true
/@types/unist/2.0.6:
resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
dev: true
@@ -2107,6 +2127,14 @@ packages:
resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==}
dev: true
/cors/2.8.5:
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
engines: {node: '>= 0.10'}
dependencies:
object-assign: 4.1.1
vary: 1.1.2
dev: false
/cosmiconfig/6.0.0:
resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==}
engines: {node: '>=8'}
@@ -4897,6 +4925,11 @@ packages:
resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==}
dev: true
/object-assign/4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
dev: false
/object-inspect/1.12.2:
resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==}
@@ -5783,6 +5816,20 @@ packages:
engines: {node: '>= 0.4'}
dev: true
/swagger-ui-dist/4.15.5:
resolution: {integrity: sha512-V3eIa28lwB6gg7/wfNvAbjwJYmDXy1Jo1POjyTzlB6wPcHiGlRxq39TSjYGVjQrUSAzpv+a7nzp7mDxgNy57xA==}
dev: false
/swagger-ui-express/4.6.0_express@4.18.2:
resolution: {integrity: sha512-ZxpQFp1JR2RF8Ar++CyJzEDdvufa08ujNUJgMVTMWPi86CuQeVdBtvaeO/ysrz6dJAYXf9kbVNhWD7JWocwqsA==}
engines: {node: '>= v0.10.32'}
peerDependencies:
express: '>=4.0.0'
dependencies:
express: 4.18.2
swagger-ui-dist: 4.15.5
dev: false
/symbol-tree/3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
dev: true

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,18 +1,26 @@
import 'express-async-errors'
import cors from 'cors'
import express, { Express, Router } from 'express'
import swaggerUi from 'swagger-ui-express'
import { Container } from 'typedi'
import {
HomeController,
UserController,
WhitelistController,
} from './controllers'
import { UserController, WhitelistController } from './controllers'
import openApiSpecs from './openapi.json'
const app: Express = express()
const homeController = Container.get(HomeController)
const whitelistController = Container.get(WhitelistController)
const userController = Container.get(UserController)
app.get('/', homeController.home.bind(HomeController))
app.use(cors())
app.use(express.static('public'))
app.use('/', swaggerUi.serve)
app.get(
'/',
swaggerUi.setup(openApiSpecs, {
customfavIcon: '/favicon.ico',
customSiteTitle: 'Zkitter Groups API',
}),
)
app.use(
'/whitelist',

View File

@@ -1,62 +0,0 @@
import { Request, Response } from 'express'
import { Service } from 'typedi'
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Zkitter Groups API</title>
</head>
<body>
<div>
<h1>ZKITTER GROUPS API</h1>
<h2>Routes</h2>
<table>
<tr>
<th>Method</th>
<th>Path</th>
<th>Response</th>
</tr>
<tr>
<td>GET</td>
<td>/whitelist?format=long|short</td>
<td>Get list of whitelisted organizations in <code>short</code> or <code>long</code> format</td>
</tr>
<tr>
<td>GET</td>
<td>/whitelist/refresh</td>
<td>Update list of whitelisted orgs and their repos. Return updated whitelist</td>
</tr>
<tr>
<td>GET</td>
<td>/user/:username?format=short|long</td>
<td>Get user <code>username</code> in <code>short</code> (only groups info) or <code>long</code> (with repos) format</td>
</tr>
<tr>
<td>GET</td>
<td>/user/:username/refresh</td>
<td>Update list of repos the user <code>username</code> contributed to and return updated user</td>
</tr>
</table>
</div>
<hr>
<footer>
<a
rel="stylesheet"
target="_blank"
href="https://github.com/zkitter/groups"
>https://github.com/zkitter/groups</a
>
</footer>
</body>
</html>
`
@Service()
export class HomeController {
async home(_: Request, res: Response) {
res.send(html)
}
}

View File

@@ -2,6 +2,5 @@
* @file Automatically generated by barrelsby.
*/
export * from './Home'
export * from './User/index'
export * from './Whitelist/index'

215
src/openapi.json Normal file
View File

@@ -0,0 +1,215 @@
{
"openapi": "3.0.3",
"info": {
"title": "Zkitter Groups - OpenAPI 3.0",
"description": "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. \n\n[GitHub](https://github.com/zkitter/groups)",
"license": {
"name": "MIT",
"url": "https://github.com/zkitter/groups/blob/main/LICENSE"
},
"version": "1.0.0"
},
"servers": [
{
"url": "https://zkitter-groups.fly.dev/"
},
{
"url": "https://zkitter-groups-staging.fly.dev/"
}
],
"tags": [
{
"name": "whitelist",
"description": "Whitelisted Organizations"
},
{
"name": "user",
"description": "GitHub User"
}
],
"paths": {
"/user/{username}": {
"get": {
"tags": ["user"],
"summary": "Get user by GitHub login/username",
"description": "",
"operationId": "getUserByGhName",
"parameters": [
{
"name": "username",
"in": "path",
"description": "The GitHub login that needs to be fetched.",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "format",
"in": "query",
"description": "response format",
"required": false,
"schema": {
"type": "string",
"enum": ["short", "long"],
"example": "long",
"default": "short"
}
}
],
"responses": {
"200": {
"description": "successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
}
}
}
},
"/user/{username}/refresh": {
"get": {
"tags": ["user"],
"summary": "Update list of repos the user contributed.",
"description": "",
"operationId": "refreshUserByGhName",
"parameters": [
{
"name": "username",
"in": "path",
"description": "The GitHub login that needs to be refreshed.",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
}
}
}
},
"/whitelist": {
"get": {
"tags": ["whitelist"],
"summary": "Get whitelisted organizations.",
"description": "",
"operationId": "getWhitelist",
"parameters": [
{
"name": "format",
"in": "query",
"description": "response format",
"required": false,
"schema": {
"type": "string",
"enum": ["short", "long"],
"example": "long",
"default": "short"
}
}
],
"responses": {
"200": {
"description": "sucessful operation",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Org"
}
}
}
}
}
}
}
},
"/whitelist/refresh": {
"get": {
"tags": ["whitelist"],
"summary": "Update list of whitelisted orgs and their repos.",
"description": "",
"operationId": "refreshWhitelist",
"responses": {
"200": {
"description": "successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"User": {
"required": ["belongsToGhContributorsGroup"],
"type": "object",
"properties": {
"belongsToGhContributorsGroup": {
"type": "boolean",
"example": true
},
"ghName": {
"type": "string",
"example": "r1oga"
},
"repos": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"Org": {
"type": "object",
"properties": {
"ghName": {
"type": "string",
"example": "stargate-protocol"
},
"snapshotId": {
"type": "string",
"example": "stgdao.eth"
},
"snapshotName": {
"type": "string",
"example": "Stargate DAO"
},
"followers": {
"type": "number",
"example": 10000
},
"repos": {
"type": "array",
"items": {
"type": "string",
"example": ["treasure-docs", "treasure-subgraph"]
}
}
}
}
}
}
}