Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add documentation endpoint #187

Draft
wants to merge 2 commits into
base: stable
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const os = require('os');

// Assuming by default that we run in 'development' environment, if no
// NODE_ENV is specified.
exports.env = process.env.NODE_ENV || 'development';
exports.host = process.env.X_HOST || os.hostname();
exports.name = process.env.npm_package_name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we take it from ../package.json the same way as in /healthcheck?

exports.version = process.env.npm_package_version;
exports.description = process.env.npm_package_description;
14 changes: 14 additions & 0 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const express = require('express');
const router = require('express-promise-router');
const bodyParser = require('body-parser');
const boolParser = require('express-query-boolean');
const swaggerJSDoc = require('swagger-jsdoc');

const morgan = require('./morgan');
const db = require('./sequelize');
Expand Down Expand Up @@ -55,7 +56,20 @@ process.on('unhandledRejection', (err) => {
}
});

const options = {}; // (1/3) stupid gimmick because fuck the library lol
options.definition = require('./swaggerDef.js'); // (2/3) cli options are slightly different
options.apis = require('./swaggerDef.js').apis;
// (3/3) so i have to make this gimmick
const swaggerSpec = swaggerJSDoc(options); // Initialize swagger-jsdoc -> returns validated swagger spec in json format

// Endpoints not requiring authorization.
GeneralRouter.get('/api-docs.json', (req, res) => { // mini-route to retrieve the docs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we move it to middlewares/ ? either to /middlewares/generic.js or create other file to store it

idea is that lib/server.js contains the routing (e.g. this route is served by these middlewares), and not the middlewares themselves (they are stored in middlewares/*

log.info('request coming from ' + req.ip + ' to ' + req.hostname);
res.setHeader('Content-Type', 'application/json');
res.setHeader('Access-Control-Allow-Origin', '*');
res.status(200).send(swaggerSpec);
});

GeneralRouter.get('/healthcheck', middlewares.healthcheck);
GeneralRouter.get('/metrics', metrics.getMetrics);
GeneralRouter.get('/metrics/requests', endpointsMetrics.getEndpointMetrics);
Expand Down
24 changes: 24 additions & 0 deletions lib/swaggerDef.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const config = require('../config');
const serverInfo = require('./info.js');

module.exports = {
info: {
// API informations (required)
title: serverInfo.name, // Title (required)
version: serverInfo.version, // Version (required)
description: serverInfo.description, // Description (optional)
termsOfService: 'https://my.aegee.eu/legal/simple',
license: {
name: 'Apache 2.0',
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
}
},
// host, // Host (optional) -- automatically taken who's serving this docs
apis: ['middlewares/*.js'], // where are the files with the comments
basePath: config.basePath, // Base path (optional)
schemes: ['http'],
externalDocs: {
description: 'Find out more about MyAEGEE',
url: 'https://myaegee.atlassian.net/wiki/spaces/GENERAL/overview'
}
};
152 changes: 152 additions & 0 deletions middlewares/bodies.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ const constants = require('../lib/constants');
const errors = require('../lib/errors');
const { sequelize } = require('../lib/sequelize');

/**
* @swagger
*
* /bodies:
* get:
* tags:
* - "Bodies"
* summary: "List all bodies"
* description: "This endpoint is to list all bodies"
* operationId: "listAllBodies"
* produces:
* - "application/json"
* responses:
* 200:
* description: "Successful operation"
* 403:
* description: "Not enough permissions"
*/
exports.listAllBodies = async (req, res) => {
if (req.query.all) {
if (!req.user) {
Expand Down Expand Up @@ -40,13 +58,60 @@ exports.listAllBodies = async (req, res) => {
});
};

/**
* @swagger
*
* /bodies/{body_id}:
* get:
* tags:
* - "Bodies"
* summary: "List specific body"
* description: "This endpoint is to list specified body"
* operationId: "listBody"
* produces:
* - "application/json"
* responses:
* 200:
* description: "Successful operation"
* 403:
* description: "Not enough permissions"
*/
exports.getBody = async (req, res) => {
return res.json({
success: true,
data: req.currentBody
});
};

/**
* @swagger
*
* /bodies:
* post:
* tags:
* - "Bodies"
* summary: "Create bodies"
* description: "This endpoint is to create bodies"
* operationId: "createBody"
* consumes:
* - "application/json"
* produces:
* - "application/json"
* parameters:
* - name: "body"
* in: "body"
* description: "The data containing information on the new body"
* required: true
* schema:
* $ref: '#/definitions/Body'
* responses:
* 201:
* description: "Successful operation"
* 400:
* description: "Invalid input"
* 409:
* description: "Duplicate entity"
*/
exports.createBody = async (req, res) => {
if (!req.permissions.hasPermission('global:create:body')) {
return errors.makeForbiddenError(res, 'Permission global:create:body is required, but not present.');
Expand All @@ -60,6 +125,35 @@ exports.createBody = async (req, res) => {
});
};

/**
* @swagger
*
* /bodies/{body_id}:
* put:
* tags:
* - "Bodies"
* summary: "Update bodies"
* description: "This endpoint is to update bodies"
* operationId: "updateBody"
* consumes:
* - "application/json"
* produces:
* - "application/json"
* parameters:
* - name: "body"
* in: "body"
* description: "The data containing information on the new body"
* required: true
* schema:
* $ref: '#/definitions/Body'
* responses:
* 200:
* description: "Successful operation"
* 400:
* description: "Invalid input"
* 409:
* description: "Duplicate entity"
*/
exports.updateBody = async (req, res) => {
if (!req.permissions.hasPermission('update:body')) {
return errors.makeForbiddenError(res, 'Permission update:body is required, but not present.');
Expand All @@ -72,6 +166,35 @@ exports.updateBody = async (req, res) => {
});
};

/**
* @swagger
*
* /bodies/{body_id}/status:
* put:
* tags:
* - "Bodies"
* summary: "Update bodies' status"
* description: "This endpoint is to update bodies' status"
* operationId: "updateBodyStatus"
* consumes:
* - "application/json"
* produces:
* - "application/json"
* parameters:
* - name: "body"
* in: "body"
* description: "The data containing information on the new body"
* required: true
* schema:
* $ref: '#/definitions/Body'
* responses:
* 200:
* description: "Successful operation"
* 400:
* description: "Invalid input"
* 403:
* description: "Unauthorised"
*/
exports.setBodyStatus = async (req, res) => {
if (!req.permissions.hasPermission('global:delete:body')) {
return errors.makeForbiddenError(res, 'Permission global:delete:body is required, but not present.');
Expand All @@ -97,6 +220,35 @@ exports.setBodyStatus = async (req, res) => {
});
};

/**
* @swagger
*
* /bodies/{body_id}/members:
* put:
* tags:
* - "Bodies"
* summary: "Add body member"
* description: "This endpoint is to add body member"
* operationId: "addBodyMember"
* consumes:
* - "application/json"
* produces:
* - "application/json"
* parameters:
* - name: "body"
* in: "body"
* description: "The data containing information on the new body"
* required: true
* schema:
* $ref: '#/definitions/Body'
* responses:
* 200:
* description: "Successful operation"
* 400:
* description: "Invalid input"
* 403:
* description: "Unauthorised"
*/
exports.createMember = async (req, res) => {
if (!req.permissions.hasPermission('create_member:body')) {
return errors.makeForbiddenError(res, 'Permission create_member:body is required, but not present.');
Expand Down
30 changes: 30 additions & 0 deletions middlewares/circles.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,36 @@ const helpers = require('../lib/helpers');
const constants = require('../lib/constants');
const { Sequelize, sequelize } = require('../lib/sequelize');

/**
* @swagger
*
* /circles:
* post:
* tags:
* - "Circles"
* summary: "Create Circle"
* description: "This endpoint is to create a Circle group"
* operationId: "createGroup"
* consumes:
* - "application/json"
* produces:
* - "application/json"
* parameters:
* - name: "data"
* in: "body"
* description: "The data containing information on the group"
* required: true
* schema:
* $ref: '#/definitions/Group'
* responses:
* 201:
* description: "Successful operation"
* 400:
* description: "Invalid input"
* 409:
* description: "Duplicate entity"
*/

exports.listAllCircles = async (req, res) => {
const where = helpers.filterBy(req.query.query, constants.FIELDS_TO_QUERY.CIRCLE);

Expand Down
Loading