Skip to content

Commit

Permalink
refactor: Apply Problem schema, update schema : HelpListResponse, Hel…
Browse files Browse the repository at this point in the history
…pCommandResponse, add 404 response, removed error 422
  • Loading branch information
princerajpoot20 committed Aug 19, 2023
1 parent 5a005f6 commit ed228cd
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 28 deletions.
42 changes: 30 additions & 12 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ paths:

/help:
get:
summary: Retrieve help information for the given command and any number of subcommands.
summary: Retrieve help information for the given command.
operationId: help
tags:
- help
Expand All @@ -237,7 +237,7 @@ paths:
in: query
style: form
explode: true
description: The command (and any subcommands) for which help information is needed. Subcommands can be separated by '/' or space ' '.
description: The command for which help information is needed.
required: true
schema:
type: string
Expand All @@ -247,22 +247,21 @@ paths:
content:
application/json:
schema:
type: object
properties:
message:
type: string
oneOf:
- $ref: '#/components/schemas/HelpListResponse'
- $ref: '#/components/schemas/HelpCommandResponse'
"400":
description: Failed to get help. The given AsyncAPI command is not valid.
description: Bad request
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
"422":
description: The given AsyncAPI document(s) is/are not valid due to invalid parameters in the request.
$ref: '#/components/schemas/Problem'
"404":
description: Command not found
content:
application/json:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
$ref: '#/components/schemas/Problem'
default:
description: Unexpected problem.
content:
Expand Down Expand Up @@ -459,6 +458,25 @@ components:
type: [object, string]
description: The diff between the two AsyncAPI documents.

HelpListResponse:
type: object
properties:
commands:
type: array
items:
type: string
description: A list of all available commands.
HelpCommandResponse:
type: object
description: Detailed help information for a specific command.
properties:
command:
type: string
description: The name of the command.
description:
type: string
description: Detailed description of the command.

Problem:
type: object
properties:
Expand Down
42 changes: 34 additions & 8 deletions src/controllers/help.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Router, Request, Response } from 'express';
import { Router, Request, Response, NextFunction } from 'express';
import { Controller } from '../interfaces';
import axios from 'axios';
import yaml from 'js-yaml';
import { ProblemException } from '../exceptions/problem.exception';

export const fetchCommands = async (user, repo) => {
try {
Expand All @@ -14,6 +15,12 @@ export const fetchCommands = async (user, repo) => {
return yaml.load(response.data);
} catch (error) {
console.error(`Error fetching commands: ${error}`);
throw new ProblemException({
type: 'fetch-commands-error',
title: 'Error Fetching Commands',
status: 500,
detail: error.message
});
}
};

Expand Down Expand Up @@ -67,13 +74,18 @@ const buildResponseObject = (matchedPathKey: string, method: string, operationDe
export class HelpController implements Controller {
public basepath = '/help';

public boot(): Router {
public async boot(): Promise<Router> {
const router: Router = Router();

router.get(/^\/help(\/.*)?$/, async (req: Request, res: Response) => {
router.get(/^\/help(\/.*)?$/, async (req: Request, res: Response, next: NextFunction) => {
const commands = getCommandsFromRequest(req);
const openapiSpec: any = await fetchCommands('asyncapi', 'server-api');
if (!openapiSpec) return res.status(500).json({ message: 'Error fetching help information' });
let openapiSpec: any;

try {
openapiSpec = await fetchCommands('asyncapi', 'server-api');
} catch (err) {
return next(err);
}

if (commands.length === 0) {
const routes = Object.keys(openapiSpec.paths).map(path => ({ command: path.replace(/^\//, ''), url: `${this.basepath}${path}` }));
Expand All @@ -82,12 +94,26 @@ export class HelpController implements Controller {

const pathKeys = Object.keys(openapiSpec.paths);
const matchedPathKey = getPathKeysMatchingCommands(commands, pathKeys);
if (!matchedPathKey) return res.status(404).json({ message: 'Failed to get help. The given AsyncAPI command is not valid.' });
if (!matchedPathKey) {
return next(new ProblemException({
type: 'invalid-asyncapi-command',
title: 'Invalid AsyncAPI Command',
status: 404,
detail: 'The given AsyncAPI command is not valid.'
}));
}

const pathInfo = openapiSpec.paths[matchedPathKey];
const method = commands.length > 1 ? 'get' : 'post';
const operationDetails = pathInfo[method];
if (!operationDetails) return res.status(404).json({ message: 'Failed to get help. The given AsyncAPI command is not valid.' });
if (!operationDetails) {
return next(new ProblemException({
type: 'invalid-asyncapi-command',
title: 'Invalid AsyncAPI Command',
status: 404,
detail: 'The given AsyncAPI command is not valid.'
}));
}

const { requestBody } = operationDetails;
let requestBodyComponent: any = {};
Expand All @@ -105,4 +131,4 @@ export class HelpController implements Controller {

return router;
}
}
}
25 changes: 17 additions & 8 deletions src/controllers/tests/help.controller.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import request from 'supertest';
import { App } from '../../app';
import { ProblemException } from '../../exceptions/problem.exception';
import { HelpController, fetchCommands } from '../help.controller';

jest.mock('../help.controller', () => ({
...(jest.requireActual('../help.controller') as any),
fetchCommands: jest.fn()
...(jest.requireActual('../help.controller') as any),
fetchCommands: jest.fn()
}));


describe('HelpController', () => {
let app;
beforeAll(async () => {
Expand Down Expand Up @@ -110,12 +110,16 @@ describe('HelpController', () => {
const response = await request(app.getServer())
.get('/v1/help/invalidCommand')
.expect(404);

expect(response.body.message).toBe('Failed to get help. The given AsyncAPI command is not valid.');

expect(response.body).toEqual({
type: 'https://api.asyncapi.com/problem/invalid-asyncapi-command',
title: 'Invalid AsyncAPI Command',
status: 404,
detail: 'The given AsyncAPI command is not valid.'
});
});

it('should return 404 error for a command without a method', async () => {

(fetchCommands as jest.Mock).mockResolvedValue({
paths: {
"/someCommand": {}
Expand All @@ -125,8 +129,13 @@ describe('HelpController', () => {
const response = await request(app.getServer())
.get('/v1/help/someCommand')
.expect(404);

expect(response.body.message).toBe('Failed to get help. The given AsyncAPI command is not valid.');

expect(response.body).toEqual({
type: 'https://api.asyncapi.com/problem/invalid-asyncapi-command',
title: 'Invalid AsyncAPI Command',
status: 404,
detail: 'The given AsyncAPI command is not valid.'
});
});
});
});

0 comments on commit ed228cd

Please sign in to comment.