Skip to content

Commit

Permalink
Merge pull request #41 from DVGY/feature=api/api-docs-and-tours-field
Browse files Browse the repository at this point in the history
add swagger docs and open api specs
  • Loading branch information
DVGY authored Oct 18, 2023
2 parents b199ba2 + ce0fd4f commit 12d177e
Show file tree
Hide file tree
Showing 12 changed files with 289 additions and 12 deletions.
22 changes: 11 additions & 11 deletions tours-server/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,27 @@ module.exports = {
es2021: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
parser: "@typescript-eslint/parser",
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 12,
project: "tsconfig.eslint.json",
project: 'tsconfig.eslint.json',
tsconfigRootDir: __dirname,
},
plugins: ["@typescript-eslint"],
plugins: ['@typescript-eslint'],
rules: {
"prefer-const": "error",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-unused-params": "off",
'prefer-const': 'error',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-unused-params': 'off',
},
overrides: [
{
files: ["test/**/*.ts"],
files: ['test/**/*.ts'],
env: { jest: true, node: true },
},
],
ignorePatterns: [".eslintrc.js"],
ignorePatterns: ['.eslintrc.js', 'src/api-docs/**'],
};
23 changes: 23 additions & 0 deletions tours-server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions tours-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"morgan": "^1.10.0",
"slugify": "^1.5.2",
"stripe": "^8.167.0",
"swagger-ui-express": "^4.1.6",
"validator": "^13.6.0",
"xss-clean": "^0.1.1"
},
Expand All @@ -49,6 +50,7 @@
"@types/morgan": "^1.9.2",
"@types/node": "^15.0.1",
"@types/supertest": "^2.0.11",
"@types/swagger-ui-express": "^4.1.3",
"@types/validator": "^13.6.3",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
Expand Down
15 changes: 15 additions & 0 deletions tours-server/src/api-docs/basicinfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const basicInfo = {
openapi: '3.0.3', // present supported openapi version
info: {
title: 'Tours.dev api', // short title.
description: 'An API to book tours', // desc.
version: '1.0.0', // version number
contact: {
name: 'Gaurav Yadav', // your name
email: '[email protected]', // your email
url: 'https://tours-api-prod.herokuapp.com', // your website
},
},
};

export { basicInfo };
152 changes: 152 additions & 0 deletions tours-server/src/api-docs/components.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
const component = {
components: {
schemas: {
// todo model
Trips: {
type: 'object', // data type
properties: {
id: {
type: 'string', // data-type
description: 'A trip id', // desc
example: '6145a6c4991f41fb47f63bfe', // example of an id
},
name: {
type: 'string', // data-type
description: 'Name of Trip', // desc
example: 'The Visitor Palace', // example of a title
unique: true,
required: true,
},
slug: {
type: 'string', // data type
description: 'Name of Trip, used in client trip search', // desc
example: 'the visitor palace', // example of a completed value
},
duration: {
type: 'number', // data type
description: 'Total Number of Days', // desc
example: 4, // example of a completed value
required: true,
},
price: {
type: 'number', // data type
description: 'Price of Trip', // desc
example: '220', // example of a completed value
},
priceDiscount: {
type: 'number', // data type
description: 'Discount on Trip', // desc
example: '10', // example of a completed value
},
difficulty: {
type: 'string', // data type
description: 'Trip difficulty level (Easy, Medium, Hard)', // desc
example: 'medium', // example of a completed value
},
ratingsAverage: {
type: 'number', // data type
description: 'Average ratings of a Trip', // desc
example: '4.4', // example of a completed value
default: 4.5,
},
ratingsQuantity: {
type: 'number',
description: 'Number of ratings of a Trip', // desc
example: '50',
default: 0,
},
summary: {
type: 'string', // data type
description: 'A short summary of Trip', // desc
example: 'This is best ............', // example of a completed value
},
description: {
type: 'string', // data type
description: 'A short description of Trip', // desc
example: 'The tours of the .....', // example of a completed value
},
imageCover: {
type: 'string', // data type
description: 'A cover photo/image url of a Trip', // des
example: 'https://www.myimageurl.com',
},
images: {
type: 'array',
description: 'All images/photos url of a Trip', // des
example: [
'https://www.myimageurl1.com',
'https://www.myimageurl2.com',
],
},
createdAt: {
type: 'string',
description: 'Timestamp when Trip was created', // des
example: 'https://www.myimageurl.com',
},
guides: {
$ref: '#/components/schemas/user',
},
startDates: {
type: 'array',
description: 'Start dates of each trip location', // des
example: [
'2021-06-19T09:00:00.000Z',
'2021-07-20T09:00:00.000Z',
'2021-08-18T09:00:00.000Z',
],
},
startLocation: {
type: 'object',
description: 'Geo JSON Point',
example: {
description: 'Banff, CAN',
type: 'Point',
coordinates: [-115.570154, 51.178456],
address: '224 Banff Ave, Banff, AB, Canada',
},
properties: {
coordinates: {
type: 'array',
},
address: {
type: 'string',
},
description: {
type: 'string',
},
},
// longitute, latitude
},
locations: {
type: 'array',
description: 'Geo JSON Points',
},

secretTrip: {
type: 'boolean',
description: 'Special Secret Trips ',
},
},
},

// error model
Error: {
type: 'object', //data type
properties: {
message: {
type: 'string', // data type
description: 'Error message', // desc
example: 'Not found', // example of an error message
},
internal_code: {
type: 'string', // data type
description: 'Error internal code', // desc
example: 'Invalid parameters', // example of an error internal code
},
},
},
},
},
};

export { component };
13 changes: 13 additions & 0 deletions tours-server/src/api-docs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { basicInfo } from './basicInfo';
import { server } from './server';
import { tag } from './tags';
import { component } from './components';
import trips from './trips';

export = {
...basicInfo,
...server,
...tag,
...component,
...trips,
};
14 changes: 14 additions & 0 deletions tours-server/src/api-docs/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const server = {
servers: [
{
url: 'http://localhost:1337/api/v1', // url
description: 'Local server', // name
},
{
url: 'https://tours-api-prod.herokuapp.com', // url
description: 'Production server', // name
},
],
};

export { server };
9 changes: 9 additions & 0 deletions tours-server/src/api-docs/tags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const tag = {
tags: [
{
name: 'An API to book tours', // name of a tag
},
],
};

export { tag };
34 changes: 34 additions & 0 deletions tours-server/src/api-docs/trips/getATrip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const getATrip = {
// method of operation
get: {
tags: ['Get A Trip'], // operation's tag.
description: 'Get A Trip', // operation's desc.
operationId: 'getATrip', // unique operation id.
parameters: [
{
name: 'id', // name of the param
in: 'path', // location of the param
schema: { type: 'string', default: null },
required: false, // Mandatory param
description: 'id of Trip', // param desc.
},
], // expected params.
// expected responses
responses: {
// response code
200: {
description: 'Get A Trip', // response desc.
content: {
// content-type
'application/json': {
schema: {
$ref: '#/components/schemas/Trips', // Todo model
},
},
},
},
},
},
};

export { getATrip };
9 changes: 9 additions & 0 deletions tours-server/src/api-docs/trips/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getATrip } from './getATrip';

export = {
paths: {
'/trips/:id': {
...getATrip,
},
},
};
5 changes: 5 additions & 0 deletions tours-server/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import xss from 'xss-clean';
import hpp from 'hpp';
import cors from 'cors';
import cookieParser from 'cookie-parser';
import swaggerUI from 'swagger-ui-express';

import tripsRouter from './routes/tripsRoutes';
import usersRouter from './routes/usersRoutes';
Expand All @@ -15,6 +16,7 @@ import bookingsRouter from './routes/bookingsRoutes';
import { createBookingsStripeWebhook } from './controllers/bookingsController';
import { errorHandler } from './utils/errorHandler';
import { stripe } from './utils/stripe';
import docs from './api-docs';

const app = express();
const allowedOrigins = ['http://localhost:3000', /\.vercel\.app$/];
Expand Down Expand Up @@ -78,6 +80,8 @@ app.use(
app.get('/', (req, res) => {
res.status(200).json({
status: 'success',
message:
'Visit https://tours-api-prod.herokuapp.com/api-docs for documentation',
});
});
app.get('/docker', (req, res) => {
Expand All @@ -86,6 +90,7 @@ app.get('/docker', (req, res) => {
data: 'Hi, I am inside docker and NGINX is looking after me',
});
});
app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(docs));

app.use('/api/v1/trips', tripsRouter);
app.use('/api/v1/users', usersRouter);
Expand Down
3 changes: 2 additions & 1 deletion tours-server/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
"typeRoots": ["src/@types", "./node_modules/@types"]
},
"include": ["src"]
"include": ["src"],
"exclude": ["src/api-docs/**"]
}

0 comments on commit 12d177e

Please sign in to comment.