Massive cleanup

Functionnal basic API calls for spells
Cleaned up some functions
Moved some files around
This commit is contained in:
Alexis
2021-07-30 12:24:11 +02:00
parent a15a6614e7
commit 4cc7c5533e
21 changed files with 334 additions and 148 deletions

View File

@@ -1,74 +1,111 @@
import express, { Application } from 'express' import express, { Application } from 'express'
import { Sequelize } from 'sequelize' import { Sequelize } from 'sequelize'
import { AuracleApiRouter } from './AuracleApiRouter'
// import ControllerBase from './class/controller.base'
export class AuracleApi { export class AuracleApi {
public app: Application public app: Application
public port: number public port: number
public base_url = '/api/v1/' public version = 'v1'
public baseUrl = `/api/${this.version}/`
private database?: Sequelize; constructor(
init: {
constructor(init: { port: any
port: any database: Sequelize
middlewares: any routers?: Array<AuracleApiRouter>
// controllers: Array<ControllerBase> modules?: Array<any>
modules?: Array<any> middlewares?: Array<any>
database?: Sequelize }
}) { ) {
this.app = express() this.app = express()
this.port = Number(init.port) this.port = Number(init.port)
this.database = init.database
if (init.modules) {
this.modules(init.modules)
}
if (init.middlewares) {
this.middlewares(init.middlewares)
}
// if (init.controllers) {
// this.controller(init.controllers)
// }
// Making sure the DB is up before init routers, modules, etc...
if (init.database) { if (init.database) {
this.db_connect(init.database) this.db_connect(init.database)
.then(() => {
// Sets up tasks to execute...
const tasks = [
this.modules(init.modules),
this.routers(init.routers),
this.middlewares(init.middlewares)
]
Promise.all(tasks)
.catch((err) => {
throw err
})
})
.catch((err) => {
console.error("App couldn't boot up with the following errors : ")
console.error(err)
})
} }
} }
private modules = (modules: Array<any>) => { /**
modules.forEach((module) => { * Links the API with a Sequelize Database Object
this.app.use(module) * @param db_driver A Sequelize instance
}) */
}
// private controller = (controllers: Array<ControllerBase>) => {
// controllers.forEach((controller) => {
// this.app.use(this.base_url + controller.path, controller.router)
// console.log(`${controller.name} chargé`)
// })
// }
private middlewares = (middleWares: {
forEach: (arg0: (middleWare: any) => void) => void;
}) => {
middleWares.forEach((middleWare) => {
this.app.use(middleWare)
})
}
private db_connect = async (db_driver: Sequelize) => { private db_connect = async (db_driver: Sequelize) => {
try { try {
await db_driver.authenticate(); const connection = await db_driver.authenticate();
console.info('Connection has been established successfully.') console.info('Connection has been established successfully.')
return connection
} catch (err) { } catch (err) {
console.error('Unable to connect to the database') console.error('Unable to connect to the database.')
console.error(err) throw err
} }
} }
/**
* Initializes the App with a bunch of modules like helmet, cors, morgan...
* @param modules An array of modules and extensions
*/
private modules = async (modules: Array<any>) => {
try {
modules.forEach((module) => {
this.app.use(module)
})
} catch (err) {
console.error('Unable to initialize modules and extensions.')
throw err
}
}
/**
* Initializes routers
* @param routers An array of AuracleApiRouter children objects
*/
private routers = async (routers: Array<AuracleApiRouter>) => {
try {
routers.forEach((router) => {
this.app.use(`${this.baseUrl}`, router.instance)
})
} catch (err) {
console.error('Unable to initialize routers.')
throw err
}
}
private middlewares = async (middleWares: {
forEach: (arg0: (middleWare: any) => void) => void;
}) => {
try {
middleWares.forEach((middleWare) => {
this.app.use(middleWare)
})
} catch (err) {
console.error('Unable to initialize middlewares.')
throw err
}
}
/**
* Allows the App to run on its given port
*/
public listen = () => { public listen = () => {
this.app.listen(this.port, () => { this.app.listen(this.port, () => {
console.log(`App listening on port ${this.port}`) console.log(`App listening on port ${this.port}`)

View File

@@ -0,0 +1,9 @@
import { AuracleApiRepository } from "./AuracleApiRepository";
export class AuracleApiController {
public repository: AuracleApiRepository
constructor(repository: AuracleApiRepository) {
this.repository = repository
}
}

View File

@@ -0,0 +1,9 @@
import { Model } from "sequelize/types";
export class AuracleApiRepository {
public model: Model<any, any>
constructor(model: Model<any, any>) {
this.model = model
}
}

View File

@@ -0,0 +1,52 @@
import { Response } from "express"
/**
* An enum that contains all the default value for the ApiResponse class
*/
enum AuracleApiMessages {
defaultValid = "La requête a été effectuée avec succès.",
defaultRedirect = "La requête redirige vers une autre URL.",
defaultClientError = "Une erreur inconnue dûe à une erreur client s'est produite",
defaultServerError = "Une erreur serveur inconnue s'est produite, veuillez contactez l'administrateur de l'application."
}
export class AuracleApiResponse {
public status: number
public message?: string
public data?: Object | Array<any>
constructor(status: number, data?: Array<any> | Object, message?: string) {
this.status = status
this.data = data
if (message) {
this.message = message
}
// If a message was not provided, gets one by default
else {
// HTTP Valid ranges
if ((this.status >= 200) && (this.status <= 299)) {
this.message = AuracleApiMessages.defaultValid
}
// HTTP Redirect ranges
else if ((this.status >= 300) && (this.status <= 399)) {
this.message = AuracleApiMessages.defaultRedirect
}
// HTTP Client Error ranges
else if ((this.status >= 400) && (this.status <= 499)) {
this.message = AuracleApiMessages.defaultClientError
}
// HTTP Server Error ranges
else if ((this.status >= 500) && (this.status <= 599)) {
this.message = AuracleApiMessages.defaultServerError
}
}
}
public send(res: Response): Response {
return res.status(this.status).json(this)
}
}

View File

@@ -0,0 +1,17 @@
import { Router, RouterOptions } from "express";
import { AuracleApiController } from "./AuracleApiController";
export abstract class AuracleApiRouter {
public instance: Router
public routerOptions: RouterOptions
public resource: string
public controller: AuracleApiController
constructor(resource: string, controller: AuracleApiController, options?: RouterOptions) {
this.resource = resource
this.routerOptions = options
this.controller = controller
this.instance = Router(this.routerOptions) as Router
}
}

View File

@@ -0,0 +1,54 @@
import express from 'express';
import { AuracleApiController } from "../common/classes/AuracleApiController";
import { AuracleApiResponse } from '../common/classes/AuracleApiResponse';
import { Spell, SpellCreationAttributes } from '../database/models/spells/Spell';
import { SpellRepository } from "../repositories/SpellRepository";
export class SpellController extends AuracleApiController {
public repository: SpellRepository
constructor() {
super(new SpellRepository)
}
public async getAll(req: express.Request, res: express.Response) {
let spells: Spell[]
try {
spells = await this.repository.fetchAll()
res = new AuracleApiResponse(200, spells).send(res)
} catch (err) {
res = new AuracleApiResponse(400).send(res)
}
}
public async getOne(req: express.Request, res: express.Response) {
const uuid = req.params.uuid
let spell: Spell
try {
spell = await this.repository.fetchOne(uuid)
res = new AuracleApiResponse(200, spell).send(res)
} catch (err) {
res = new AuracleApiResponse(400).send(res)
}
}
public async createOne(req: express.Request, res: express.Response) {
const spell = {
name: req.body.name,
description: req.body.description,
level: req.body.level,
charge: req.body.charge,
cost: req.body.cost,
isRitual: req.body.isRitual
} as SpellCreationAttributes
try {
const newSpell = await this.repository.createOne(spell)
res = new AuracleApiResponse(201, newSpell).send(res)
} catch (err) {
console.log(err)
}
}
}

View File

@@ -7,15 +7,6 @@ export let AuracleDatabaseDriver: Sequelize;
// Creates the sequelize instance // Creates the sequelize instance
AuracleDatabaseDriver = new Sequelize(dbConfig) AuracleDatabaseDriver = new Sequelize(dbConfig)
/**
* If the environement is production...
*/
if (process.env.NODE_ENV != 'production') {
AuracleDatabaseDriver.sync({
force: true
})
}
/** /**
* Fetches all Typescript files from a given directory * Fetches all Typescript files from a given directory
* *
@@ -49,3 +40,12 @@ models.forEach(modelPath => {
const registerModel = require(modelPath).default as Function const registerModel = require(modelPath).default as Function
registerModel() registerModel()
}) })
/**
* If the environement is production, sync the DB
*/
if (process.env.NODE_ENV != 'production') {
AuracleDatabaseDriver.sync({
force: true,
})
}

View File

@@ -20,9 +20,5 @@ export const dbConfig: Options = {
* Sequelize Hooks * Sequelize Hooks
* Docs : https://sequelize.org/master/manual/hooks.html * Docs : https://sequelize.org/master/manual/hooks.html
*/ */
hooks: { hooks: {}
beforeDefine: (columns: any, model: ModelOptions<Model<any, any>>) => {
model.tableName = tablePrefix + model.tableName
}
}
} }

View File

@@ -3,7 +3,6 @@ import { DataTypes, Model, Optional } from "sequelize";
import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver"; import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver";
interface IngredientAttributes { interface IngredientAttributes {
id: number
uuid: string uuid: string
name: string name: string
description: string description: string
@@ -11,10 +10,9 @@ interface IngredientAttributes {
published: boolean published: boolean
} }
interface IngredientCreationAttributes extends Optional<IngredientAttributes, 'id'> { } interface IngredientCreationAttributes extends Optional<IngredientAttributes, 'uuid'> { }
export class Ingredient extends Model<IngredientAttributes, IngredientCreationAttributes> implements IngredientAttributes { export class Ingredient extends Model<IngredientAttributes, IngredientCreationAttributes> implements IngredientAttributes {
public readonly id!: number
public readonly uuid!: string public readonly uuid!: string
public name!: string public name!: string
public description!: string public description!: string
@@ -28,16 +26,12 @@ export class Ingredient extends Model<IngredientAttributes, IngredientCreationAt
export default () => { export default () => {
Ingredient.init( Ingredient.init(
{ {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
uuid: { uuid: {
type: DataTypes.UUID, type: DataTypes.UUID,
allowNull: false,
unique: true, unique: true,
defaultValue: DataTypes.UUIDV4 allowNull: false,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
}, },
name: { name: {
type: DataTypes.STRING, type: DataTypes.STRING,
@@ -55,7 +49,7 @@ export default () => {
} }
}, },
{ {
tableName: 'ingredients', tableName: 'au_ingredients',
sequelize: AuracleDatabaseDriver, sequelize: AuracleDatabaseDriver,
} }
) )

View File

@@ -3,7 +3,6 @@ import { DataTypes, Model, Optional } from "sequelize";
import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver"; import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver";
interface MetaSchoolAttributes { interface MetaSchoolAttributes {
id: number
uuid: string uuid: string
name: string name: string
description: string description: string
@@ -11,10 +10,9 @@ interface MetaSchoolAttributes {
published: boolean published: boolean
} }
interface MetaSchoolCreationAttributes extends Optional<MetaSchoolAttributes, 'id'> { } interface MetaSchoolCreationAttributes extends Optional<MetaSchoolAttributes, 'uuid'> { }
export class MetaSchool extends Model<MetaSchoolAttributes, MetaSchoolCreationAttributes> implements MetaSchoolAttributes { export class MetaSchool extends Model<MetaSchoolAttributes, MetaSchoolCreationAttributes> implements MetaSchoolAttributes {
public readonly id!: number
public readonly uuid!: string public readonly uuid!: string
public name!: string public name!: string
public description!: string public description!: string
@@ -28,16 +26,12 @@ export class MetaSchool extends Model<MetaSchoolAttributes, MetaSchoolCreationAt
export default () => { export default () => {
MetaSchool.init( MetaSchool.init(
{ {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
uuid: { uuid: {
type: DataTypes.UUID, type: DataTypes.UUID,
allowNull: false,
unique: true, unique: true,
defaultValue: DataTypes.UUIDV4 allowNull: false,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
}, },
name: { name: {
type: DataTypes.STRING, type: DataTypes.STRING,
@@ -55,7 +49,7 @@ export default () => {
} }
}, },
{ {
tableName: 'meta_schools', tableName: 'au_meta_schools',
sequelize: AuracleDatabaseDriver, sequelize: AuracleDatabaseDriver,
} }
) )

View File

@@ -3,7 +3,6 @@ import { DataTypes, Model, Optional } from "sequelize";
import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver"; import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver";
interface SchoolAttributes { interface SchoolAttributes {
id: number
uuid: string uuid: string
name: string name: string
description: string description: string
@@ -11,10 +10,9 @@ interface SchoolAttributes {
published: boolean published: boolean
} }
interface SchoolCreationAttributes extends Optional<SchoolAttributes, 'id'> { } interface SchoolCreationAttributes extends Optional<SchoolAttributes, 'uuid'> { }
export class School extends Model<SchoolAttributes, SchoolCreationAttributes> implements SchoolAttributes { export class School extends Model<SchoolAttributes, SchoolCreationAttributes> implements SchoolAttributes {
public readonly id!: number
public readonly uuid!: string public readonly uuid!: string
public name!: string public name!: string
public description!: string public description!: string
@@ -28,16 +26,12 @@ export class School extends Model<SchoolAttributes, SchoolCreationAttributes> im
export default () => { export default () => {
School.init( School.init(
{ {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
uuid: { uuid: {
type: DataTypes.UUID, type: DataTypes.UUID,
allowNull: false,
unique: true, unique: true,
defaultValue: DataTypes.UUIDV4 allowNull: false,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
}, },
name: { name: {
type: DataTypes.STRING, type: DataTypes.STRING,
@@ -55,7 +49,7 @@ export default () => {
} }
}, },
{ {
tableName: 'schools', tableName: 'au_schools',
sequelize: AuracleDatabaseDriver, sequelize: AuracleDatabaseDriver,
} }
) )

View File

@@ -1,55 +1,49 @@
import { DataTypes, Model, Optional } from "sequelize"; import { DataTypes, Model, Optional, TableHints } from "sequelize";
import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver"; import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver";
interface SpellAttributes { interface SpellAttributes {
id: number
uuid: string uuid: string
name: string name: string
description: string description: string
level: number level?: number
charge: number charge?: number
cost: string cost?: string
isRitual: boolean isRitual?: boolean
published: boolean published?: boolean
public: boolean public?: boolean
} }
interface SpellCreationAttributes extends Optional<SpellAttributes, 'id'> { } export interface SpellCreationAttributes extends Optional<SpellAttributes, 'uuid'> { }
export class SpellModel extends Model<SpellAttributes, SpellCreationAttributes> implements SpellAttributes { export class Spell extends Model<SpellAttributes, SpellCreationAttributes> implements SpellAttributes {
public readonly id!: number
public readonly uuid!: string public readonly uuid!: string
public name!: string public name!: string
public description!: string public description!: string
public level: number public level?: number
public charge: number public charge?: number
public cost: string public cost?: string
public isRitual: boolean public isRitual?: boolean
public published: boolean public published?: boolean
public public: boolean public public?: boolean
public readonly createdAt!: Date; public readonly createdAt!: Date;
public readonly updatedAt!: Date; public readonly updatedAt!: Date;
} }
export default () => { export default async () => {
SpellModel.init( Spell.init(
{ {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
uuid: { uuid: {
type: DataTypes.UUID, type: DataTypes.UUID,
allowNull: false,
unique: true, unique: true,
defaultValue: DataTypes.UUIDV4 allowNull: false,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
}, },
name: { name: {
type: DataTypes.STRING, type: DataTypes.STRING,
@@ -88,7 +82,7 @@ export default () => {
}, },
}, },
{ {
tableName: 'spells', tableName: 'au_spells',
sequelize: AuracleDatabaseDriver, sequelize: AuracleDatabaseDriver,
} }
) )

View File

@@ -3,17 +3,15 @@ import { DataTypes, Model, Optional } from "sequelize";
import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver"; import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver";
interface VariableAttributes { interface VariableAttributes {
id: number
uuid: string uuid: string
description: string description: string
published: boolean published: boolean
} }
interface VariableCreationAttributes extends Optional<VariableAttributes, 'id'> { } interface VariableCreationAttributes extends Optional<VariableAttributes, 'uuid'> { }
export class Variable extends Model<VariableAttributes, VariableCreationAttributes> implements VariableAttributes { export class Variable extends Model<VariableAttributes, VariableCreationAttributes> implements VariableAttributes {
public readonly id!: number
public readonly uuid!: string public readonly uuid!: string
public description!: string public description!: string
@@ -26,16 +24,12 @@ export class Variable extends Model<VariableAttributes, VariableCreationAttribut
export default () => { export default () => {
Variable.init( Variable.init(
{ {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
uuid: { uuid: {
type: DataTypes.UUID, type: DataTypes.UUID,
allowNull: false,
unique: true, unique: true,
defaultValue: DataTypes.UUIDV4 allowNull: false,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
}, },
description: { description: {
type: DataTypes.STRING, type: DataTypes.STRING,
@@ -48,7 +42,7 @@ export default () => {
} }
}, },
{ {
tableName: 'variables', tableName: 'au_variables',
sequelize: AuracleDatabaseDriver, sequelize: AuracleDatabaseDriver,
} }
) )

View File

@@ -3,15 +3,13 @@ import { DataTypes, Model, Optional } from "sequelize";
import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver"; import { AuracleDatabaseDriver } from "../../AuracleDatabaseDriver";
interface PermissionAttributes { interface PermissionAttributes {
id: number
uuid: string uuid: string
slug: string slug: string
} }
interface PermissionCreationAttributes extends Optional<PermissionAttributes, 'id'> { } interface PermissionCreationAttributes extends Optional<PermissionAttributes, 'uuid'> { }
export class Permission extends Model<PermissionAttributes, PermissionCreationAttributes> implements PermissionAttributes { export class Permission extends Model<PermissionAttributes, PermissionCreationAttributes> implements PermissionAttributes {
public readonly id!: number
public readonly uuid!: string public readonly uuid!: string
public slug!: string public slug!: string
@@ -22,16 +20,12 @@ export class Permission extends Model<PermissionAttributes, PermissionCreationAt
export default () => { export default () => {
Permission.init( Permission.init(
{ {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
uuid: { uuid: {
type: DataTypes.UUID, type: DataTypes.UUID,
allowNull: false,
unique: true, unique: true,
defaultValue: DataTypes.UUIDV4 allowNull: false,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
}, },
slug: { slug: {
type: DataTypes.STRING, type: DataTypes.STRING,
@@ -40,7 +34,7 @@ export default () => {
}, },
}, },
{ {
tableName: 'permissions', tableName: 'au_permissions',
sequelize: AuracleDatabaseDriver, sequelize: AuracleDatabaseDriver,
} }
) )

View File

@@ -47,7 +47,7 @@ export default () => {
}, },
}, },
{ {
tableName: 'roles', tableName: 'au_roles',
sequelize: AuracleDatabaseDriver, sequelize: AuracleDatabaseDriver,
} }
) )

View File

@@ -70,7 +70,7 @@ export default () => {
}, },
}, },
{ {
tableName: 'users', tableName: 'au_users',
sequelize: AuracleDatabaseDriver, sequelize: AuracleDatabaseDriver,
} }
) )

View File

@@ -14,11 +14,16 @@ import express from 'express'
import { AuracleApi } from './common/classes/AuracleApi' import { AuracleApi } from './common/classes/AuracleApi'
import { AuracleDatabaseDriver } from './database/AuracleDatabaseDriver' import { AuracleDatabaseDriver } from './database/AuracleDatabaseDriver'
import { SpellRouter } from './routes/SpellRouter';
const apiPort = process.env.API_PORT const apiPort = process.env.API_PORT
const app = new AuracleApi({ const app = new AuracleApi({
port: apiPort, port: apiPort,
middlewares: [], middlewares: [],
routers: [
new SpellRouter()
],
modules: [ modules: [
express.json({ limit: '10kb' }), express.json({ limit: '10kb' }),
morgan('dev'), morgan('dev'),

View File

@@ -0,0 +1,20 @@
import { AuracleApiRepository } from "../common/classes/AuracleApiRepository"
import { Spell, SpellCreationAttributes } from "../database/models/spells/Spell"
export class SpellRepository extends AuracleApiRepository {
constructor() {
super(new Spell)
}
public async fetchAll(): Promise<Spell[]> {
return Spell.findAll()
}
public async fetchOne(uuid: string): Promise<Spell> {
return Spell.findByPk(uuid)
}
public async createOne(spell: SpellCreationAttributes): Promise<Spell> {
return Spell.create(spell)
}
}

23
src/routes/SpellRouter.ts Normal file
View File

@@ -0,0 +1,23 @@
import { AuracleApiRouter } from "../common/classes/AuracleApiRouter";
import { SpellController } from "../controllers/SpellController";
export class SpellRouter extends AuracleApiRouter {
public controller: SpellController
constructor() {
super('/spells', new SpellController)
this.initRoutes()
}
public initRoutes() {
// GET: /spells
this.instance.get(this.resource, this.controller.getAll.bind(this.controller))
// GET: /spells/uuid
this.instance.get(`${this.resource}/:uuid`, this.controller.getOne.bind(this.controller))
// POST: /spells
this.instance.post(this.resource, this.controller.createOne.bind(this.controller))
}
}

View File

@@ -11,7 +11,7 @@
"sourceMap": true, "sourceMap": true,
"outDir": "./dist", "outDir": "./dist",
"esModuleInterop": true, "esModuleInterop": true,
"baseUrl": "./src", "baseUrl": "/src",
"incremental": true, "incremental": true,
"types": [ "types": [
"node", "node",