1
0
Эх сурвалжийг харах

remove duplicated http fallback funcs

Aneurin Barker Snook 1 жил өмнө
parent
commit
f7a3887dd4
5 өөрчлөгдсөн 74 нэмэгдсэн , 104 устгасан
  1. 17 18
      src/account/api.ts
  2. 19 20
      src/herd/api.ts
  3. 5 32
      src/http.ts
  4. 1 1
      src/main.ts
  5. 32 33
      src/task/api.ts

+ 17 - 18
src/account/api.ts

@@ -3,9 +3,8 @@ import type { Context } from '../types'
 import { ObjectId } from 'mongodb'
 import type { RequestHandler } from 'express'
 import type { WithId } from 'mongodb'
-import { validate as v } from '@edge/misc-utils'
 import type { Account, AccountCreate, AccountUpdate } from './types'
-import { sendBadRequest, sendForbidden, sendNotFound, sendUnauthorized } from '../http'
+import { http, validate as v } from '@edge/misc-utils'
 
 /** Create an account. */
 export function createAccount({ model }: Context): RequestHandler {
@@ -29,7 +28,7 @@ export function createAccount({ model }: Context): RequestHandler {
       const input = readRequestData(req.body)
 
       const account = await model.account.create(input.account)
-      if (!account) return sendNotFound(res, next, { reason: 'unexpectedly failed to get new account' })
+      if (!account) return http.notFound(res, next, { reason: 'unexpectedly failed to get new account' })
 
       const output: ResponseData = { account }
       res.send(output)
@@ -38,7 +37,7 @@ export function createAccount({ model }: Context): RequestHandler {
       const name = (err as Error).name
       if (name === 'ValidateError') {
         const ve = err as v.ValidateError
-        return sendBadRequest(res, next, { param: ve.param, reason: ve.message })
+        return http.badRequest(res, next, { param: ve.param, reason: ve.message })
       }
       return next(err)
     }
@@ -52,18 +51,18 @@ export function deleteAccount({ model }: Context): AuthRequestHandler {
   }
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     // Get account ID and assert access
     const id = req.params.id || req.account._id
-    if (!id) return sendBadRequest(res, next)
-    if (!req.account._id.equals(id)) return sendForbidden(res, next)
+    if (!id) return http.badRequest(res, next)
+    if (!req.account._id.equals(id)) return http.forbidden(res, next)
 
     try {
       // Delete account
       /** @todo delete related data */
       const account = await model.account.collection.findOneAndDelete({ _id: new ObjectId(id) })
-      if (!account) return sendNotFound(res, next)
+      if (!account) return http.notFound(res, next)
 
       const output: ResponseData = { account }
       res.send(output)
@@ -81,11 +80,11 @@ export function getAccount(): AuthRequestHandler {
   }
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     // Get account ID and assert access
     const id = req.params.id || req.account._id
-    if (!req.account._id.equals(id)) return sendForbidden(res, next)
+    if (!req.account._id.equals(id)) return http.forbidden(res, next)
 
     try {
       // Send output
@@ -126,11 +125,11 @@ export function loginAccount({ auth, model }: Context): RequestHandler {
 
       // Get account
       const account = await model.account.collection.findOne({ email: input.account.email })
-      if (!account) return sendNotFound(res, next)
+      if (!account) return http.notFound(res, next)
 
       // Validate password
       const password = model.account.hashPassword(input.account.password, account.passwordSalt)
-      if (password !== account.password) return sendBadRequest(res, next, { reason: 'invalid password' })
+      if (password !== account.password) return http.badRequest(res, next, { reason: 'invalid password' })
 
       // Create JWT
       const token = await auth.sign(account._id)
@@ -143,7 +142,7 @@ export function loginAccount({ auth, model }: Context): RequestHandler {
       const name = (err as Error).name
       if (name === 'ValidateError') {
         const ve = err as v.ValidateError
-        return sendBadRequest(res, next, { param: ve.param, reason: ve.message })
+        return http.badRequest(res, next, { param: ve.param, reason: ve.message })
       }
       return next(err)
     }
@@ -168,22 +167,22 @@ export function updateAccount({ model }: Context): AuthRequestHandler {
   })
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     // Get account ID and assert access
     const id = req.params.id || req.account._id
-    if (!req.account._id.equals(id)) return sendForbidden(res, next)
+    if (!req.account._id.equals(id)) return http.forbidden(res, next)
 
     try {
       // Read input
       const input = readRequestData(req.body)
       if (!input.account.email && !input.account.password) {
-        return sendBadRequest(res, next, { reason: 'no changes' })
+        return http.badRequest(res, next, { reason: 'no changes' })
       }
 
       // Update account
       const account = await model.account.update(id, input.account)
-      if (!account) return sendNotFound(res, next)
+      if (!account) return http.notFound(res, next)
 
       // Send output
       const output: ResponseData = { account }
@@ -193,7 +192,7 @@ export function updateAccount({ model }: Context): AuthRequestHandler {
       const name = (err as Error).name
       if (name === 'ValidateError') {
         const ve = err as v.ValidateError
-        return sendBadRequest(res, next, { param: ve.param, reason: ve.message })
+        return http.badRequest(res, next, { param: ve.param, reason: ve.message })
       }
       return next(err)
     }

+ 19 - 20
src/herd/api.ts

@@ -4,8 +4,7 @@ import { ObjectId } from 'mongodb'
 import type { SearchResult } from '../api'
 import type { WithId } from 'mongodb'
 import type { Herd, HerdCreate, HerdUpdate } from './types'
-import { query, validate as v } from '@edge/misc-utils'
-import { sendBadRequest, sendForbidden, sendNotFound, sendUnauthorized } from '../http'
+import { http, query, validate as v } from '@edge/misc-utils'
 
 /** Create a herd. */
 export function createHerd({ model }: Context): AuthRequestHandler {
@@ -25,18 +24,18 @@ export function createHerd({ model }: Context): AuthRequestHandler {
   })
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     try {
       // Read input
       const input = readRequestData(req.body)
 
       // Assert ability to assign herd
-      if (!req.account._id.equals(input.herd._account)) return sendForbidden(res, next)
+      if (!req.account._id.equals(input.herd._account)) return http.forbidden(res, next)
 
       // Create herd
       const herd = await model.herd.create({ ...input.herd, _account: req.account._id })
-      if (!herd) return sendNotFound(res, next, { reason: 'unexpectedly failed to get new herd' })
+      if (!herd) return http.notFound(res, next, { reason: 'unexpectedly failed to get new herd' })
 
       // Send output
       const output: ResponseData = { herd }
@@ -46,7 +45,7 @@ export function createHerd({ model }: Context): AuthRequestHandler {
       const name = (err as Error).name
       if (name === 'ValidateError') {
         const ve = err as v.ValidateError
-        return sendBadRequest(res, next, { param: ve.param, reason: ve.message })
+        return http.badRequest(res, next, { param: ve.param, reason: ve.message })
       }
       return next(err)
     }
@@ -64,13 +63,13 @@ export function deleteHerd({ model }: Context): AuthRequestHandler {
   }
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     try {
       // Assert access to herd
       const herd = await model.herd.collection.findOne({ _id: new ObjectId(req.params.id) })
-      if (!herd) return sendNotFound(res, next)
-      if (!req.account._id.equals(herd._account)) return sendForbidden(res, next)
+      if (!herd) return http.notFound(res, next)
+      if (!req.account._id.equals(herd._account)) return http.forbidden(res, next)
 
       // Delete herd
       const result = await model.herd.delete(herd._id)
@@ -97,13 +96,13 @@ export function getHerd({ model }: Context): AuthRequestHandler {
   }
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     try {
       // Assert access to herd
       const herd = await model.herd.collection.findOne({ _id: new ObjectId(req.params.id) })
-      if (!herd) return sendNotFound(res, next)
-      if (!req.account._id.equals(herd._account)) return sendForbidden(res, next)
+      if (!herd) return http.notFound(res, next)
+      if (!req.account._id.equals(herd._account)) return http.forbidden(res, next)
 
       // Send output
       const output: ResponseData = { herd }
@@ -122,7 +121,7 @@ export function searchHerds({ model }: Context): AuthRequestHandler {
   }>
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     // Read parameters
     const limit = query.integer(req.query.limit, 1, 100) || 10
@@ -180,23 +179,23 @@ export function updateHerd({ model }: Context): AuthRequestHandler {
   })
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     try {
       // Assert access to herd
       let herd = await model.herd.collection.findOne({ _id: new ObjectId(req.params.id) })
-      if (!herd) return sendNotFound(res, next)
-      if (!req.account._id.equals(herd._account)) return sendForbidden(res, next)
+      if (!herd) return http.notFound(res, next)
+      if (!req.account._id.equals(herd._account)) return http.forbidden(res, next)
 
       // Read input
       const input = readRequestData(req.body)
       if (!input.herd._account && !input.herd.name) {
-        return sendBadRequest(res, next, { reason: 'no changes' })
+        return http.badRequest(res, next, { reason: 'no changes' })
       }
 
       // Assert ability to assign herd, if specified in update
       if (input.herd._account) {
-        if (!req.account._id.equals(input.herd._account)) return sendForbidden(res, next)
+        if (!req.account._id.equals(input.herd._account)) return http.forbidden(res, next)
       }
 
       // Update herd
@@ -204,7 +203,7 @@ export function updateHerd({ model }: Context): AuthRequestHandler {
         ...input.herd,
         _account: input.herd._account && new ObjectId(input.herd._account) || undefined,
       })
-      if (!herd) return sendNotFound(res, next)
+      if (!herd) return http.notFound(res, next)
 
       // Send output
       const output: ResponseData = { herd }
@@ -214,7 +213,7 @@ export function updateHerd({ model }: Context): AuthRequestHandler {
       const name = (err as Error).name
       if (name === 'ValidateError') {
         const ve = err as v.ValidateError
-        return sendBadRequest(res, next, { param: ve.param, reason: ve.message })
+        return http.badRequest(res, next, { param: ve.param, reason: ve.message })
       }
       return next(err)
     }

+ 5 - 32
src/http.ts

@@ -2,11 +2,12 @@ import * as account from './account/api'
 import * as herd from './herd/api'
 import * as task from './task/api'
 import type { Context } from './types'
+import type { ErrorRequestHandler } from 'express'
 import express from 'express'
-import type { ErrorRequestHandler, NextFunction, Response } from 'express'
+import { http } from '@edge/misc-utils'
 
 /** Create an Express application. */
-export function createExpress(ctx: Context) {
+function createExpress(ctx: Context) {
   // Initialize app with JSON and auth middleware
   const app = express()
   app.use(express.json())
@@ -45,7 +46,7 @@ export function createExpress(ctx: Context) {
   // Add middleware to handle any errors forwarded from previous handlers via `next(err)`
   const catchError: ErrorRequestHandler = (err, req, res, next) => {
     if (!res.headersSent) {
-      sendInternalServerError(res, next, { reason: (err as Error).message })
+      http.internalServerError(res, next, { reason: (err as Error).message })
     }
     ctx.log.error(err)
   }
@@ -60,32 +61,4 @@ export function createExpress(ctx: Context) {
   return app
 }
 
-/** Send a 400 Bad Request error response. */
-export function sendBadRequest(res: Response, next: NextFunction, data?: Record<string, unknown>) {
-  res.status(400).send({ message: 'Bad Request', ...data })
-  next()
-}
-
-/** Send a 403 Forbidden error response. */
-export function sendForbidden(res: Response, next: NextFunction, data?: Record<string, unknown>) {
-  res.status(403).send({ message: 'Forbidden', ...data })
-  next()
-}
-
-/** Send a 500 Internal Server Error response. */
-export function sendInternalServerError(res: Response, next: NextFunction, data?: Record<string, unknown>) {
-  res.status(500).send({ message: 'Internal Server Error', ...data })
-  next()
-}
-
-/** Send a 404 Not Found error response. */
-export function sendNotFound(res: Response, next: NextFunction, data?: Record<string, unknown>) {
-  res.status(404).send({ message: 'Not Found', ...data })
-  next()
-}
-
-/** Send a 401 Unauthorized error response. */
-export function sendUnauthorized(res: Response, next: NextFunction, data?: Record<string, unknown>) {
-  res.status(401).send({ message: 'Unauthorized', ...data })
-  next()
-}
+export default createExpress

+ 1 - 1
src/main.ts

@@ -1,7 +1,7 @@
 import type { SignalConstants } from 'os'
 import createAuth from './auth'
 import createDatabase from './db'
-import { createExpress } from './http'
+import createExpress from './http'
 import createLogger from './log'
 import process from 'process'
 import type { Config, Context } from './types'

+ 32 - 33
src/task/api.ts

@@ -4,8 +4,7 @@ import { ObjectId } from 'mongodb'
 import type { SearchResult } from '../api'
 import type { WithId } from 'mongodb'
 import type { Task, TaskCreate, TaskUpdate } from './types'
-import { query, validate as v } from '@edge/misc-utils'
-import { sendBadRequest, sendForbidden, sendNotFound, sendUnauthorized } from '../http'
+import { http, query, validate as v } from '@edge/misc-utils'
 
 /** Create a task. */
 export function createTask({ model }: Context): AuthRequestHandler {
@@ -28,26 +27,26 @@ export function createTask({ model }: Context): AuthRequestHandler {
   })
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     try {
       // Read input
       const input = readRequestData(req.body)
 
       // Assert ability to assign task
-      if (!req.account._id.equals(input.task._account)) return sendForbidden(res, next)
+      if (!req.account._id.equals(input.task._account)) return http.forbidden(res, next)
 
       // Assert access to herd
       const herd = await model.herd.collection.findOne({ _id: new ObjectId(input.task._herd) })
-      if (!herd) return sendNotFound(res, next, { reason: 'herd not found' })
-      if (!req.account._id.equals(herd._account)) return sendForbidden(res, next)
+      if (!herd) return http.notFound(res, next, { reason: 'herd not found' })
+      if (!req.account._id.equals(herd._account)) return http.forbidden(res, next)
 
       const task = await model.task.create({
         ...input.task,
         _herd: new ObjectId(input.task._herd),
         _account: new ObjectId(input.task._account),
       })
-      if (!task) return sendNotFound(res, next, { reason: 'unexpectedly failed to get new task' })
+      if (!task) return http.notFound(res, next, { reason: 'unexpectedly failed to get new task' })
 
       const output: ResponseData = { task }
       res.send(output)
@@ -56,7 +55,7 @@ export function createTask({ model }: Context): AuthRequestHandler {
       const name = (err as Error).name
       if (name === 'ValidateError') {
         const ve = err as v.ValidateError
-        return sendBadRequest(res, next, { param: ve.param, reason: ve.message })
+        return http.badRequest(res, next, { param: ve.param, reason: ve.message })
       }
       return next(err)
     }
@@ -70,13 +69,13 @@ export function deleteTask({ model }: Context): AuthRequestHandler {
   }
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     try {
       // Assert access to task
       const task = await model.task.collection.findOne({ _id: new ObjectId(req.params.id) })
-      if (!task) return sendNotFound(res, next)
-      if (!req.account._id.equals(task._account)) return sendForbidden(res, next)
+      if (!task) return http.notFound(res, next)
+      if (!req.account._id.equals(task._account)) return http.forbidden(res, next)
 
       // Delete task
       await model.task.collection.deleteOne({ _id: task._id })
@@ -98,13 +97,13 @@ export function getTask({ model }: Context): AuthRequestHandler {
   }
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     try {
       // Assert access to task
       const task = await model.task.collection.findOne({ _id: new ObjectId(req.params.id) })
-      if (!task) return sendNotFound(res, next)
-      if (!req.account._id.equals(task._account)) return sendForbidden(res, next)
+      if (!task) return http.notFound(res, next)
+      if (!req.account._id.equals(task._account)) return http.forbidden(res, next)
 
       // Send output
       const output: ResponseData = { task }
@@ -130,18 +129,18 @@ export function moveTask({ model }: Context): AuthRequestHandler {
   }
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     try {
       // Read position parameter
-      if (!req.params.position) return sendBadRequest(res, next)
+      if (!req.params.position) return http.badRequest(res, next)
       const position = parseInt(req.params.position)
-      if (isNaN(position) || position < 1) return sendBadRequest(res, next)
+      if (isNaN(position) || position < 1) return http.badRequest(res, next)
 
       // Assert access to task
       const task = await model.task.collection.findOne({ _id: new ObjectId(req.params.id) })
-      if (!task) return sendNotFound(res, next)
-      if (!req.account._id.equals(task._account)) return sendForbidden(res, next)
+      if (!task) return http.notFound(res, next)
+      if (!req.account._id.equals(task._account)) return http.forbidden(res, next)
 
       // Update task
       const result = await model.task.move(task._id, position)
@@ -168,7 +167,7 @@ export function searchTasks({ model }: Context): AuthRequestHandler {
   }>
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     // Read parameters
     const herd = req.params.herd || undefined
@@ -187,7 +186,7 @@ export function searchTasks({ model }: Context): AuthRequestHandler {
       try {
         filter._herd = new ObjectId(herd)
       } catch (err) {
-        return sendBadRequest(res, next, { reason: 'invalid herd' })
+        return http.badRequest(res, next, { reason: 'invalid herd' })
       }
     }
     if (search) filter.$text = { $search: search }
@@ -228,13 +227,13 @@ export function toggleTaskDone({ model }: Context): AuthRequestHandler {
   }
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     try {
       // Assert access to task
       let task = await model.task.collection.findOne({ _id: new ObjectId(req.params.id) })
-      if (!task) return sendNotFound(res, next)
-      if (!req.account._id.equals(task._account)) return sendForbidden(res, next)
+      if (!task) return http.notFound(res, next)
+      if (!req.account._id.equals(task._account)) return http.forbidden(res, next)
 
       // Update to switch task done status
       task = await model.task.collection.findOneAndUpdate({ _id: task._id }, { $set: { done: !task.done }}, { returnDocument: 'after' })
@@ -271,30 +270,30 @@ export function updateTask({ model }: Context): AuthRequestHandler {
   })
 
   return async function (req, res, next) {
-    if (!req.account) return sendUnauthorized(res, next)
+    if (!req.account) return http.unauthorized(res, next)
 
     try {
       // Assert access to task
       let task = await model.task.collection.findOne({ _id: new ObjectId(req.params.id) })
-      if (!task) return sendNotFound(res, next)
-      if (!req.account._id.equals(task._account)) return sendForbidden(res, next)
+      if (!task) return http.notFound(res, next)
+      if (!req.account._id.equals(task._account)) return http.forbidden(res, next)
 
       // Read input
       const input = readRequestData(req.body)
       if (Object.keys(input.task).length < 1) {
-        return sendBadRequest(res, next, { reason: 'no changes' })
+        return http.badRequest(res, next, { reason: 'no changes' })
       }
 
       // Assert ability to assign task, if specified in update
       if (input.task._account) {
-        if (!req.account._id.equals(input.task._account)) return sendForbidden(res, next)
+        if (!req.account._id.equals(input.task._account)) return http.forbidden(res, next)
       }
 
       // Assert access to herd, if specified in update
       if (input.task._herd) {
         const herd = await model.task.collection.findOne({ _id: new ObjectId(input.task._herd) })
-        if (!herd) return sendNotFound(res, next, { reason: 'herd not found' })
-        if (!req.account._id.equals(herd._account)) return sendForbidden(res, next)
+        if (!herd) return http.notFound(res, next, { reason: 'herd not found' })
+        if (!req.account._id.equals(herd._account)) return http.forbidden(res, next)
       }
 
       // Update task
@@ -303,7 +302,7 @@ export function updateTask({ model }: Context): AuthRequestHandler {
         _herd: input.task._herd && new ObjectId(input.task._herd) || undefined,
         _account: input.task._account && new ObjectId(input.task._account) || undefined,
       })
-      if (!task) return sendNotFound(res, next)
+      if (!task) return http.notFound(res, next)
 
       // Send output
       const output: ResponseData = { task }
@@ -313,7 +312,7 @@ export function updateTask({ model }: Context): AuthRequestHandler {
       const name = (err as Error).name
       if (name === 'ValidateError') {
         const ve = err as v.ValidateError
-        return sendBadRequest(res, next, { param: ve.param, reason: ve.message })
+        return http.badRequest(res, next, { param: ve.param, reason: ve.message })
       }
       return next(err)
     }