-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathexpress-callback.js
More file actions
127 lines (116 loc) · 3.63 KB
/
express-callback.js
File metadata and controls
127 lines (116 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { hrtime } from 'node:process'
import getStatusByError from './error-status.js'
import { parseParams } from './params.js'
/**
* @typedef {import('express-serve-static-core').Request} Request
* @typedef {import('express-serve-static-core').Response} Response
* @typedef {import('openapi-backend').Context} Context
* @typedef {import('./api.js').Logger} Logger
*/
/**
* Make an express callback for the controller
* @param {object} params
* @param {Function} params.controller
* @param {object} params.specification
* @param {boolean=} params.errorDetails
* @param {Logger=} params.logger
* @param {object=} params.meta
* @param {boolean=} params.mock
* @returns {Function}
*/
export const makeExpressCallback
= ({ controller, specification, errorDetails, logger, meta, mock }) =>
/**
* Handle controller
* @async
* @param {Context} context
* @param {Request} request
* @param {Response} response
* @returns {Promise<any>}
*/
async (context, request, response) => {
const startTime = hrtime()
try {
const allParameters = {
...(context.request?.params || {}),
...(context.request?.query || {})
}
const parameters = parseParams({
query: allParameters,
spec: context.operation.parameters,
mock
})
const url = `${request.protocol}://${request.get('Host')}${request.originalUrl}`
const ipHeader = request.headers?.['x-forwarded-for']
const ipString = Array.isArray(ipHeader) ? ipHeader[0] : ipHeader
const ip = ipString
? ipString.split(',')[0].trim()
: (request.socket?.remoteAddress || request.ip || '-')
const { method } = request
const userAgent = request.headers?.['user-agent'] || request.get('user-agent') || '-'
const feedback = {
context,
request,
response,
parameters,
specification,
post: request.body,
url,
logger,
meta
}
const responseBody = await controller(feedback)
const responseTime = hrtime(startTime)[1] / 1000000 // convert to milliseconds
try {
logger?.debug({
url,
parameters,
post: request.body,
response: responseBody,
method,
ip,
userAgent,
responseTime,
statusCode: response.statusCode || 200,
message: 'access'
})
} catch (logError) {
// Prevent logging errors from affecting the request
console.error('Logger failed:', logError)
}
return responseBody
} catch (error) {
const errorCodeStatus = getStatusByError(error)
try {
if (errorCodeStatus >= 500) {
logger?.error(error)
} else {
logger?.warn(error)
}
} catch (logError) {
// Prevent logging errors from affecting the request
console.error('Logger failed:', logError)
}
response.status(errorCodeStatus)
if (errorDetails) {
return {
errors: [
{
message: error.message,
value: error.valueOf(),
type: error.constructor.name
}
],
status: errorCodeStatus,
timestamp: new Date(),
message: error.message
}
}
return {
errors: error.errors || error.value?.errors,
status: errorCodeStatus,
timestamp: new Date(),
message: error.message
}
}
}