Add swagger 📚
continuous-integration/drone/push Build is passing Details

pull/19/head
Emre KARTAL 1 year ago
parent d389b58930
commit e86a35118d

@ -17,6 +17,8 @@
"@types/cors": "^2.8.13",
"@types/express": "^4.17.16",
"@types/jsonwebtoken": "^9.0.1",
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.6",
"nodemon": "^2.0.20",
"ts-node": "^10.9.1",
"typescript": "^4.9.5"
@ -33,6 +35,8 @@
"express": "^4.18.2",
"joi": "^17.8.1",
"jsonwebtoken": "^9.0.0",
"mongoose": "^6.9.0"
"mongoose": "^6.9.0",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.0"
}
}

@ -2,22 +2,23 @@ import express, { Application } from 'express';
import cors from 'cors';
import cookieParser from 'cookie-parser';
import bodyParser from 'body-parser';
import Controller from './controllers/interfaces/IController';
import IController from './controllers/interfaces/IController';
import mongoose from 'mongoose';
import swaggerUi from "swagger-ui-express";
import { specs } from './utils/swagger';
class App {
public express: Application;
public port: number;
public dataBase: null;
public server: any;
constructor(controllers: Controller[], port: number) {
constructor(controllers: IController[], port: number) {
this.express = express();
this.port = port;
this.initDatabase();
this.initMiddleware();
this.initControllers(controllers);
this.initSwagger();
}
private initMiddleware(): void {
@ -31,15 +32,15 @@ class App {
}));
}
private initControllers(controllers: Controller[]): void {
controllers.forEach((controller: Controller) => {
private initControllers(controllers: IController[]): void {
controllers.forEach((controller: IController) => {
this.express.use('/api', controller.router);
});
}
public listen(): void {
this.express.listen(this.port, () => {
console.log(`[server] : App listening on the port ${this.port}`);
console.log(`⚡️[server] : App listening on the port ${this.port}`);
});
}
@ -49,6 +50,11 @@ class App {
.then(() => console.log("Connect to MongoDB database successfully"))
.catch(error => console.log("Error connecting : " + error));
}
public initSwagger(): void {
this.express.use("/swagger", swaggerUi.serve, swaggerUi.setup(specs),);
console.log(`Docs available at /${this.port}/swagger`);
}
}
export default App;

@ -1,8 +1,8 @@
import { Router } from 'express';
interface Controller {
interface IController {
path: string;
router: Router;
}
export default Controller;
export default IController;

@ -18,8 +18,79 @@ class SpotifyController implements IController {
}
initRoutes() {
/**
* @swagger
* /api/spotify/exchange:
* get:
* summary: Initiate the Spotify login flow
* description: Redirect the user to the Spotify login page for authorization
* tags:
* - Spotify
* parameters:
* - in: query
* name: redirectUrl
* schema:
* type: string
* description: The URL to redirect the user after Spotify authorization (optional)
* responses:
* 302:
* description: Redirecting to Spotify login page
* 400:
* description: Bad request - Cannot connect to Spotify
*/
this.router.get(`${this.path}/exchange`, this.login);
/**
* @swagger
* /api/spotify/callback:
* get:
* summary: Handle Spotify callback and exchange code for access token
* description: Handle Spotify callback and exchange the received code for an access token
* tags:
* - Spotify
* responses:
* 302:
* description: Redirecting with access token information
* 400:
* description: Bad request - Error connecting to Spotify
*/
this.router.get(`${this.path}/callback`, this.getAccessToken);
/**
* @swagger
* /api/spotify/refresh:
* get:
* summary: Refresh the Spotify access token using a refresh token
* description: Refresh the Spotify access token using a refresh token
* tags:
* - Spotify
* parameters:
* - in: query
* name: refresh_token
* schema:
* type: string
* required: true
* description: The refresh token obtained during the initial authorization
* responses:
* 200:
* description: Successfully refreshed access token
* content:
* application/json:
* schema:
* type: object
* properties:
* access_token:
* type: string
* description: The new access token
* refresh_token:
* type: string
* description: The new refresh token
* expires_in:
* type: number
* description: The time until the access token expires (in seconds)
* 400:
* description: Bad request - Cannot refresh the access token
*/
this.router.get(`${this.path}/refresh`, this.getRefreshToken);
}

@ -24,28 +24,410 @@ class UserController implements IController {
}
private initRoutes(): void {
/**
* @swagger
* /api/auth/register:
* post:
* summary: Register a new user
* description: Register a new user with the provided details
* tags:
* - Authentication
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* default: john.doe@example.com
* password:
* type: string
* default: stringPassword123
* name:
* type: string
* default: john_doe
* tokenSpotify:
* type: string
* responses:
* 201:
* description: User registered successfully
* 400:
* description: Bad request - Invalid input data
* 401:
* description: Unauthorized - Spotify token is invalid
* 409:
* description: Conflict - Email or username is already in use
* 500:
* description: Internal Server Error - Spotify account not authorized or not found
*/
this.router.post(
`${this.authPath}/register`,
validationMiddleware(validator.register),
this.register
);
/**
* @swagger
* /api/auth/login:
* post:
* summary: Login a user
* description: Login with the provided email and password
* tags:
* - Authentication
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* default: john.doe@example.com
* password:
* type: string
* default: stringPassword123
* responses:
* 200:
* description: User logged in successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* token:
* type: string
* 400:
* description: Bad request - Invalid input data
*/
this.router.post(
`${this.authPath}/login`,
validationMiddleware(validator.login),
this.login
);
/**
* @swagger
* /api/user:
* get:
* summary: Get user information
* description: Get information about the authenticated user
* tags:
* - User
* security:
* - bearerAuth: []
* responses:
* 200:
* description: User logged in successfully
* 401:
* description: Unauthorized - Invalid or missing authentication token
*/
this.router.get(`${this.path}`, authenticator, this.getUser);
/**
* @swagger
* /api/users:
* get:
* summary: Get information about multiple users
* description: Get information about multiple users based on provided user ids
* tags:
* - User
* security:
* - bearerAuth: []
* parameters:
* - in: query
* name: ids
* schema:
* type: string
* description: Comma-separated list of user ids
* responses:
* 200:
* description: Users information retrieved successfully
* 401:
* description: Unauthorized - Invalid or missing authentication token
* 400:
* description: Bad request - Invalid input data
*/
this.router.get(`${this.path}s`, authenticator, this.getUsers);
/**
* @swagger
* /api/user:
* delete:
* summary: Delete the authenticated user
* description: Delete the authenticated user and associated data
* tags:
* - User
* security:
* - bearerAuth: []
* responses:
* 204:
* description: User deleted successfully
* 401:
* description: Unauthorized - Invalid or missing authentication token
* 404:
* description: User not found
*/
this.router.delete(`${this.path}`, authenticator, this.deleteUser);
/**
* @swagger
* /api/user/nextTo:
* get:
* summary: Get users near the authenticated user
* description: Get information about users near the authenticated user based on location
* tags:
* - User
* security:
* - bearerAuth: []
* parameters:
* - in: query
* name: longitude
* schema:
* type: number
* description: Longitude of the user's current location
* - in: query
* name: latitude
* schema:
* type: number
* description: Latitude of the user's current location
* - in: query
* name: currentMusic
* schema:
* type: string
* description: The ID of the currently playing music
* responses:
* 201:
* description: Users near the authenticated user retrieved successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* data:
* type: array
* 401:
* description: Unauthorized - Invalid or missing authentication token
* 400:
* description: Bad request - Invalid input data
*/
this.router.get(`${this.path}/nextTo`, authenticator, this.getUserNext);
/**
* @swagger
* /api/user/musics/{id}:
* delete:
* summary: Delete a music from the authenticated user's liked list
* description: Delete a music from the authenticated user's liked list by music id
* tags:
* - User
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: id
* schema:
* type: string
* description: The ID of the music to delete
* responses:
* 200:
* description: Music deleted successfully
* 401:
* description: Unauthorized - Invalid or missing authentication token
* 404:
* description: Music not found
*/
this.router.delete(`${this.path}/musics/:id`, authenticator, this.deleteMusic);
/**
* @swagger
* /api/user/musics:
* post:
* summary: Add a music to the authenticated user's liked list
* description: Add a music to the authenticated user's liked list
* tags:
* - User
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* musicId:
* type: string
* description: The ID of the music to add
* userId:
* type: string
* description: The ID of the user who liked the music
* responses:
* 201:
* description: Music added to liked list successfully
* 401:
* description: Unauthorized - Invalid or missing authentication token
* 400:
* description: Bad request - Invalid input data
*/
this.router.post(`${this.path}/musics`, authenticator, this.addMusic);
/**
* @swagger
* /api/user/musics:
* get:
* summary: Get the list of musics liked by the authenticated user
* description: Get the list of musics liked by the authenticated user
* tags:
* - User
* security:
* - bearerAuth: []
* responses:
* 200:
* description: List of musics retrieved successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* musics:
* type: array
* 401:
* description: Unauthorized - Invalid or missing authentication token
*/
this.router.get(`${this.path}/musics`, authenticator, this.getMusics);
/**
* @swagger
* /api/user/name:
* put:
* summary: Update the name of the authenticated user
* description: Update the name of the authenticated user
* tags:
* - User
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* name:
* type: string
* description: The new name for the user
* responses:
* 200:
* description: User name updated successfully
* 401:
* description: Unauthorized - Invalid or missing authentication token
* 400:
* description: Bad request - Invalid input data
* 409:
* description: Conflict - The provided name is already in use by another user
*/
this.router.put(`${this.path}/name`, authenticator, this.setName);
/**
* @swagger
* /api/user/email:
* put:
* summary: Update the email of the authenticated user
* description: Update the email of the authenticated user
* tags:
* - User
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* format: email
* description: The new email for the user
* responses:
* 200:
* description: User email updated successfully
* 401:
* description: Unauthorized - Invalid or missing authentication token
* 400:
* description: Bad request - Invalid input data
* 409:
* description: Conflict - The provided email is already in use by another user
*/
this.router.put(`${this.path}/email`, authenticator, this.setEmail);
/**
* @swagger
* /api/user/image:
* put:
* summary: Update the profile image of the authenticated user
* description: Update the profile image of the authenticated user
* tags:
* - User
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* image:
* type: string
* format: base64
* description: The new profile image for the user (base64 encoded)
* responses:
* 200:
* description: User profile image updated successfully
* 401:
* description: Unauthorized - Invalid or missing authentication token
* 500:
* description: Internal Server Error - Unable to update the profile image
*/
this.router.put(`${this.path}/image`, authenticator, this.setImage);
this.router.put(`${this.path}/password`, authenticator, this.setPassword);
/**
* @swagger
* /api/user/password:
* put:
* summary: Update the password of the authenticated user
* description: Update the password of the authenticated user
* tags:
* - User
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* oldPassword:
* type: string
* description: The current password of the user
* newPassword:
* type: string
* description: The new password for the user
* responses:
* 200:
* description: User password updated successfully
* 401:
* description: Unauthorized - Invalid or missing authentication token
* 500:
* description: Internal Server Error - Unable to update the password
*/
this.router.put(`${this.path}/password`, authenticator, this.setPassword);
}
private register = async (

@ -0,0 +1,34 @@
import swaggerJsdoc from "swagger-jsdoc";
const options = {
definition: {
openapi: "3.0.1",
info: {
title: "FLAD API",
version: "1.0.0",
description:
"This is the Express API for the Flad project.",
contact: {
name: "Flad Dev",
url: "code",
email: "fladdevpro@gmail.com",
},
},
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
}
}
},
security: [{
bearerAuth: ["read"]
}]
},
apis: ["./dist/**/*.js"],
};
export const specs = swaggerJsdoc(options);

@ -7,7 +7,7 @@ import { MusicServiceProvider } from "../../models/MusicServiceProvider";
const keyRemember = 'rememberUser';
export const register = (resgisterCredential: RegisterCredentials) => {
export const register = (registerCredential: RegisterCredentials) => {
//@ts-ignore
return async dispatch => {
try {
@ -18,7 +18,7 @@ export const register = (resgisterCredential: RegisterCredentials) => {
}
const resp = await axios.post(
configs.API_URL + '/auth/register',
resgisterCredential,
registerCredential,
config
)
const token = resp.data.token;

Loading…
Cancel
Save