feat: refactored server to use ts and improved folder structure
This commit is contained in:
38
server/src/app.ts
Normal file
38
server/src/app.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import http from 'http'
|
||||
import express, { Application } from 'express'
|
||||
import initDebug from 'debug'
|
||||
|
||||
import { registerMiddlewares } from './middlewares'
|
||||
|
||||
import indexRouter from './routes'
|
||||
import usersRouter from './routes/users'
|
||||
|
||||
import { normalizePort } from './helpers/port'
|
||||
import { getErrorCb, getListeningCb } from './helpers/server-callbacks'
|
||||
import { registerApis } from './routes/api/register'
|
||||
|
||||
const PORT = normalizePort(process.env.PORT || '6595')
|
||||
|
||||
const debug = initDebug('deemix-gui:server')
|
||||
const app: Application = express()
|
||||
const server = http.createServer(app)
|
||||
|
||||
/* === Middlewares === */
|
||||
registerMiddlewares(app)
|
||||
|
||||
/* === Routes === */
|
||||
app.use('/', indexRouter)
|
||||
app.use('/users', usersRouter)
|
||||
|
||||
/* === APIs === */
|
||||
registerApis(app)
|
||||
|
||||
/* === Config === */
|
||||
app.set('port', PORT)
|
||||
|
||||
/* === Server port === */
|
||||
server.listen(PORT)
|
||||
|
||||
/* === Server callbacks === */
|
||||
server.on('error', getErrorCb(PORT))
|
||||
server.on('listening', getListeningCb(server, debug))
|
||||
4
server/src/helpers/paths.ts
Normal file
4
server/src/helpers/paths.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import path from 'path'
|
||||
|
||||
export const ROOT_DIR = path.resolve('../')
|
||||
export const WEBUI_DIR = path.join(ROOT_DIR, 'webui', 'public')
|
||||
22
server/src/helpers/port.ts
Normal file
22
server/src/helpers/port.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Port } from '../types'
|
||||
|
||||
/**
|
||||
* Normalize a port into a number, string, or false.
|
||||
*
|
||||
* @since 0.0.0
|
||||
*/
|
||||
export function normalizePort(portString: string): Port {
|
||||
const port = parseInt(portString, 10)
|
||||
|
||||
if (isNaN(port)) {
|
||||
// named pipe
|
||||
return portString
|
||||
}
|
||||
|
||||
if (port >= 0) {
|
||||
// port number
|
||||
return port
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
47
server/src/helpers/server-callbacks.ts
Normal file
47
server/src/helpers/server-callbacks.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import http from 'http'
|
||||
import type { Debugger } from 'debug'
|
||||
|
||||
/**
|
||||
* Event listener for HTTP server "error" event.
|
||||
*
|
||||
* @since 0.0.0
|
||||
*/
|
||||
export function getErrorCb(port: number | string | boolean) {
|
||||
return (error: any) => {
|
||||
if (error.syscall !== 'listen') {
|
||||
throw error
|
||||
}
|
||||
|
||||
const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port
|
||||
|
||||
// handle specific listen errors with friendly messages
|
||||
switch (error.code) {
|
||||
case 'EACCES': {
|
||||
console.error(bind + ' requires elevated privileges')
|
||||
process.exit(1)
|
||||
}
|
||||
case 'EADDRINUSE': {
|
||||
console.error(bind + ' is already in use')
|
||||
process.exit(1)
|
||||
}
|
||||
default:
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener for HTTP server "listening" event.
|
||||
*
|
||||
* @since 0.0.0
|
||||
*/
|
||||
export function getListeningCb(server: http.Server, debug: Debugger) {
|
||||
return () => {
|
||||
const addr = server.address()
|
||||
|
||||
if (addr) {
|
||||
const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port
|
||||
debug('Listening on ' + bind)
|
||||
}
|
||||
}
|
||||
}
|
||||
13
server/src/middlewares.ts
Normal file
13
server/src/middlewares.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { Application } from 'express'
|
||||
import logger from 'morgan'
|
||||
import express from 'express'
|
||||
import cookieParser from 'cookie-parser'
|
||||
import { WEBUI_DIR } from './helpers/paths'
|
||||
|
||||
export function registerMiddlewares(app: Application) {
|
||||
app.use(logger('dev'))
|
||||
app.use(express.json())
|
||||
app.use(express.urlencoded({ extended: false }))
|
||||
app.use(cookieParser())
|
||||
app.use(express.static(WEBUI_DIR))
|
||||
}
|
||||
3
server/src/routes/api/delete/index.ts
Normal file
3
server/src/routes/api/delete/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { ApiHandler } from '../../../types'
|
||||
|
||||
export default [] as ApiHandler[]
|
||||
3
server/src/routes/api/get/index.ts
Normal file
3
server/src/routes/api/get/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import sample from './sample'
|
||||
|
||||
export default [sample]
|
||||
11
server/src/routes/api/get/sample.ts
Normal file
11
server/src/routes/api/get/sample.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { ApiHandler } from '../../../types'
|
||||
|
||||
const path: ApiHandler['path'] = '/sample'
|
||||
|
||||
const handler: ApiHandler['handler'] = (_, res) => {
|
||||
res.send('Mandi')
|
||||
}
|
||||
|
||||
const apiHandler: ApiHandler = { path, handler }
|
||||
|
||||
export default apiHandler
|
||||
3
server/src/routes/api/patch/index.ts
Normal file
3
server/src/routes/api/patch/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { ApiHandler } from '../../../types'
|
||||
|
||||
export default [] as ApiHandler[]
|
||||
3
server/src/routes/api/post/index.ts
Normal file
3
server/src/routes/api/post/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { ApiHandler } from '../../../types'
|
||||
|
||||
export default [] as ApiHandler[]
|
||||
42
server/src/routes/api/register.ts
Normal file
42
server/src/routes/api/register.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import type { Application } from 'express'
|
||||
import type { ApiHandler } from '../../types'
|
||||
|
||||
import getEndpoints from './get'
|
||||
import deleteEndpoints from './delete'
|
||||
import postEndpoints from './post'
|
||||
import patchEndpoints from './patch'
|
||||
|
||||
const prependApiPath = (path: string) => `/api${path}`
|
||||
|
||||
interface Method {
|
||||
method: string
|
||||
endpoints: ApiHandler[]
|
||||
}
|
||||
|
||||
const methods: Method[] = [
|
||||
{
|
||||
method: 'get',
|
||||
endpoints: getEndpoints
|
||||
},
|
||||
{
|
||||
method: 'delete',
|
||||
endpoints: deleteEndpoints
|
||||
},
|
||||
{
|
||||
method: 'post',
|
||||
endpoints: postEndpoints
|
||||
},
|
||||
{
|
||||
method: 'patch',
|
||||
endpoints: patchEndpoints
|
||||
}
|
||||
]
|
||||
|
||||
export function registerApis(app: Application) {
|
||||
methods.forEach(({ method, endpoints }) => {
|
||||
endpoints.forEach(endpoint => {
|
||||
// @ts-ignore
|
||||
app[method](prependApiPath(endpoint.path), endpoint.handler)
|
||||
})
|
||||
})
|
||||
}
|
||||
14
server/src/routes/index.ts
Normal file
14
server/src/routes/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import express from 'express'
|
||||
|
||||
const router = express.Router()
|
||||
|
||||
/**
|
||||
* GET home page
|
||||
*
|
||||
* @since 0.0.0
|
||||
*/
|
||||
router.get('/', (_, res) => {
|
||||
res.render('index', { title: 'Express' })
|
||||
})
|
||||
|
||||
export default router
|
||||
14
server/src/routes/users.ts
Normal file
14
server/src/routes/users.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import express from 'express'
|
||||
|
||||
const router = express.Router()
|
||||
|
||||
/**
|
||||
* GET users listing.
|
||||
*
|
||||
* @since 0.0.0
|
||||
*/
|
||||
router.get('/', (_, res) => {
|
||||
res.send('respond with a resource')
|
||||
})
|
||||
|
||||
export default router
|
||||
8
server/src/types.ts
Normal file
8
server/src/types.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { RequestHandler } from 'express'
|
||||
|
||||
export type Port = number | string | boolean
|
||||
|
||||
export interface ApiHandler {
|
||||
path: string
|
||||
handler: RequestHandler
|
||||
}
|
||||
Reference in New Issue
Block a user