Skip to content

Commit

Permalink
feat: install swagger, vision, inert for documentation and joi for va…
Browse files Browse the repository at this point in the history
…lidation
  • Loading branch information
kOaDT committed Sep 18, 2021
1 parent 770b3cd commit 625e588
Show file tree
Hide file tree
Showing 13 changed files with 345 additions and 14 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ For dev environnement, you can build the env with `make build-dev` then run with

For production environnement, you can build the env with `make build-prod` then run with `make prod`

Go on: [kitstarter-api.local:5000/api/v1/hello](kitstarter-api.local:5000/api/v1/hello)

## TYPESCRIPT JOI/INTERFACES

If you need to use Joi for response validation (in other words, if you create a new schema in /src/schema), you shouldn't create corresponding interfaces manually. You have to run :

```
npm run types
```

This will create automatically your interfaces.
Joi is used to build route documentation and to validate route params, query, response, etc.

## TESTS

This project use Chai and Mocha for units tests
Expand All @@ -59,3 +72,7 @@ Run tests :
```
make tests
```

## DOCUMENTATION API

[kitstarter-api.local:5000/api/v1/documentation](kitstarter-api.local:5000/api/v1/documentation)
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"prettier:base": "prettier --parser typescript --single-quote",
"prettier:check": "npm run prettier:base -- --list-different \"src/**/*.{ts,tsx}\"",
"prettier:write": "npm run prettier:base -- --write \"src/**/*.{ts,tsx}\"",
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -c kitstarter"
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -c kitstarter",
"types": "ts-node ./src/helpers/schemasToInterface.ts"
},
"lint-staged": {
"*.{ts,tsx}": "eslint --cache --fix",
Expand All @@ -35,14 +36,20 @@
"homepage": "https://github.com/LeoGrambert/TS-api-kitstarter/blob/develop/README.md",
"dependencies": {
"@hapi/hapi": "^20.1.5",
"@hapi/inert": "^6.0.4",
"@hapi/vision": "^6.1.0",
"dotenv": "^10.0.0",
"joi": "^17.4.2",
"mysql2": "^2.3.0",
"tslog": "^3.2.2",
"typeorm": "^0.2.37"
},
"devDependencies": {
"@types/chai": "^4.2.21",
"@types/hapi__hapi": "^20.0.9",
"@types/hapi__inert": "^5.2.3",
"@types/hapi__vision": "^5.5.3",
"@types/joi": "^17.2.3",
"@types/mocha": "^9.0.0",
"@types/node": "^16.9.2",
"@typescript-eslint/eslint-plugin": "^4.31.1",
Expand All @@ -51,7 +58,9 @@
"eslint": "^7.32.0",
"eslint-import-resolver-typescript": "^2.5.0",
"eslint-plugin-import": "^2.24.2",
"hapi-swagger": "^14.2.4",
"husky": "^7.0.2",
"joi-to-typescript": "^2.2.1",
"lint-staged": "^11.1.2",
"mocha": "^9.1.1",
"nodemon": "^2.0.12",
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/starterCtrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const sayHello = async (request: Request, h: ResponseToolkit): Promise<ResponseO
const params: Record<string, string> = {
name: request.params.name || '👋',
};
return genericHandler(h, getMessage, params, 200, 'text/plain');
return genericHandler(h, getMessage, params, 200);
};

export { sayHello };
19 changes: 19 additions & 0 deletions src/core/plugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as Inert from '@hapi/inert';
import * as Vision from '@hapi/vision';
import * as HapiSwagger from 'hapi-swagger';
import swaggerOptions from '../plugins/swagger';

const plugins: Array<any> = [
{
plugin: Inert,
},
{
plugin: Vision,
},
{
plugin: HapiSwagger,
options: swaggerOptions,
},
];

export default plugins;
3 changes: 3 additions & 0 deletions src/core/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { starterRoutes } from '../routes/starter';
import logger from '../helpers/logger';
import connection from './connection';
import { ApiError } from '../classes/ApiError';
import plugins from './plugins';

export let server: Server;

Expand Down Expand Up @@ -36,6 +37,8 @@ export const init = async function (): Promise<Server> {

server.realm.modifiers.route.prefix = '/api/v1';

await server.register(plugins);

server.route(starterRoutes);

return server;
Expand Down
26 changes: 26 additions & 0 deletions src/helpers/schemasToInterface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { convertFromDirectory } from 'joi-to-typescript';
import { ApiError } from '../classes/ApiError';
import logger from './logger';

async function types(): Promise<void> {
logger.info('🌴 Running joi-to-typescript...');

try {
const result = await convertFromDirectory({
schemaDirectory: './src/schemas',
typeOutputDirectory: './src/interfaces',
debug: process.env.NODE_ENV === 'development',
});
logger.info(result ? '🥂 Completed joi-to-typescript' : '😱 Failed to run joi-to-typescript');
} catch (err: any) {
let currentError = err;
if (!(currentError instanceof ApiError)) {
currentError = new ApiError(err.status, err.message);
currentError.originalErr = err;
}
throw currentError;
}
}

types();
11 changes: 11 additions & 0 deletions src/interfaces/Starter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* This file was automatically generated by joi-to-typescript
* Do not modify this file manually
*/

/**
* a starter schema definition
*/
export interface IStarter {
message: string;
}
6 changes: 6 additions & 0 deletions src/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* This file was automatically generated by joi-to-typescript
* Do not modify this file manually
*/

export * from './Starter';
12 changes: 12 additions & 0 deletions src/plugins/swagger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as HapiSwagger from 'hapi-swagger';
import * as Package from '../../package.json';

const swaggerOptions: HapiSwagger.RegisterOptions = {
info: {
title: 'Kitstarter API Documentation',
description: 'Kitstarter API (v1) using Typescript with Hapi and Docker.',
version: Package.version,
},
};

export default swaggerOptions;
24 changes: 22 additions & 2 deletions src/routes/starter.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,35 @@
import { ServerRoute } from '@hapi/hapi';
import { sayHello } from '../controllers/starterCtrl';
import Joi from 'joi';
import { StarterSchema } from '../schemas/StarterSchema';

export const starterRoutes: ServerRoute[] = [
{
method: 'GET',
path: '/hello',
handler: sayHello,
options: {
description: 'Route test for kitstarter',
notes: 'Say hello to a stranger',
tags: ['api', 'starter'],
handler: sayHello,
response: {
schema: Joi.array().items(StarterSchema),
failAction: 'log',
},
},
},
{
method: 'GET',
path: '/hello/{name}',
handler: sayHello,
options: {
description: 'Route test for kitstarter',
notes: 'Say hello to someone',
tags: ['api', 'starter'],
handler: sayHello,
response: {
schema: Joi.array().items(StarterSchema),
failAction: 'log',
},
},
},
];
8 changes: 8 additions & 0 deletions src/schemas/StarterSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import joi from 'joi';

export const StarterSchema = joi
.object({
message: joi.string().required(),
})
.meta({ className: 'IStarter' })
.description('a starter schema definition');
9 changes: 6 additions & 3 deletions src/services/starter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Request } from '@hapi/hapi';
import { IStarter } from '../interfaces';

const getMessage = (params: Record<string, any>): string =>
`Hi ${params.name.charAt(0).toUpperCase() + params.name.slice(1)}`;
const getMessage = (params: Record<string, any>): IStarter => {
return {
message: `Hi ${params.name.charAt(0).toUpperCase() + params.name.slice(1)}`,
};
};

export { getMessage };
Loading

0 comments on commit 625e588

Please sign in to comment.