mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-02-23 15:19:35 +02:00
lib/request: use async/await, simplify error handling
This commit is contained in:
parent
b030eec1f5
commit
7765f9d7a1
3 changed files with 59 additions and 66 deletions
|
@ -207,23 +207,10 @@ const byErrorCode = Object.assign(Object.create(null), {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const addErrorInfo = (err, errorCode, errorText, responseId) => {
|
|
||||||
if (byErrorCode[errorCode]) {
|
|
||||||
Object.assign(err, byErrorCode[errorCode])
|
|
||||||
if (errorCode) err.hafasErrorCode = errorCode
|
|
||||||
if (errorText) err.hafasErrorMessage = errorText
|
|
||||||
} else {
|
|
||||||
err.code = errorCode || null
|
|
||||||
err.message = errorText || errorCode || null
|
|
||||||
err.responseId = responseId || null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
ACCESS_DENIED,
|
ACCESS_DENIED,
|
||||||
INVALID_REQUEST,
|
INVALID_REQUEST,
|
||||||
NOT_FOUND,
|
NOT_FOUND,
|
||||||
SERVER_ERROR,
|
SERVER_ERROR,
|
||||||
byErrorCode,
|
byErrorCode,
|
||||||
addErrorInfo,
|
|
||||||
}
|
}
|
||||||
|
|
111
lib/request.js
111
lib/request.js
|
@ -1,7 +1,5 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const DEV = process.env.NODE_ENV === 'dev'
|
|
||||||
|
|
||||||
const ProxyAgent = require('https-proxy-agent')
|
const ProxyAgent = require('https-proxy-agent')
|
||||||
const {isIP} = require('net')
|
const {isIP} = require('net')
|
||||||
const {Agent: HttpsAgent} = require('https')
|
const {Agent: HttpsAgent} = require('https')
|
||||||
|
@ -9,12 +7,11 @@ const roundRobin = require('@derhuerst/round-robin-scheduler')
|
||||||
const {randomBytes} = require('crypto')
|
const {randomBytes} = require('crypto')
|
||||||
const createHash = require('create-hash')
|
const createHash = require('create-hash')
|
||||||
const pick = require('lodash/pick')
|
const pick = require('lodash/pick')
|
||||||
const captureStackTrace = DEV ? require('capture-stack-trace') : () => {}
|
|
||||||
const {stringify} = require('qs')
|
const {stringify} = require('qs')
|
||||||
const Promise = require('pinkie-promise')
|
const Promise = require('pinkie-promise')
|
||||||
const {Request, fetch} = require('fetch-ponyfill')({Promise})
|
const {Request, fetch} = require('fetch-ponyfill')({Promise})
|
||||||
const {parse: parseContentType} = require('content-type')
|
const {parse: parseContentType} = require('content-type')
|
||||||
const {addErrorInfo} = require('./errors')
|
const {byErrorCode} = require('./errors')
|
||||||
|
|
||||||
const proxyAddress = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || null
|
const proxyAddress = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || null
|
||||||
const localAddresses = process.env.LOCAL_ADDRESS || null
|
const localAddresses = process.env.LOCAL_ADDRESS || null
|
||||||
|
@ -66,16 +63,16 @@ const randomizeUserAgent = (userAgent) => {
|
||||||
|
|
||||||
const md5 = input => createHash('md5').update(input).digest()
|
const md5 = input => createHash('md5').update(input).digest()
|
||||||
|
|
||||||
const request = (ctx, userAgent, reqData) => {
|
const request = async (ctx, userAgent, reqData) => {
|
||||||
const {profile, opt} = ctx
|
const {profile, opt} = ctx
|
||||||
|
|
||||||
const body = profile.transformReqBody(ctx, {
|
const rawReqBody = profile.transformReqBody(ctx, {
|
||||||
// todo: is it `eng` actually?
|
// todo: is it `eng` actually?
|
||||||
// RSAG has `deu` instead of `de`
|
// RSAG has `deu` instead of `de`
|
||||||
lang: opt.language || profile.defaultLanguage || 'en',
|
lang: opt.language || profile.defaultLanguage || 'en',
|
||||||
svcReqL: [reqData]
|
svcReqL: [reqData]
|
||||||
})
|
})
|
||||||
Object.assign(body, pick(profile, [
|
Object.assign(rawReqBody, pick(profile, [
|
||||||
'client', // client identification
|
'client', // client identification
|
||||||
'ext', // ?
|
'ext', // ?
|
||||||
'ver', // HAFAS protocol version
|
'ver', // HAFAS protocol version
|
||||||
|
@ -86,7 +83,7 @@ const request = (ctx, userAgent, reqData) => {
|
||||||
agent: getAgent(),
|
agent: getAgent(),
|
||||||
method: 'post',
|
method: 'post',
|
||||||
// todo: CORS? referrer policy?
|
// todo: CORS? referrer policy?
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(rawReqBody),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept-Encoding': 'gzip, br, deflate',
|
'Accept-Encoding': 'gzip, br, deflate',
|
||||||
|
@ -129,56 +126,66 @@ const request = (ctx, userAgent, reqData) => {
|
||||||
const fetchReq = new Request(url, req)
|
const fetchReq = new Request(url, req)
|
||||||
profile.logRequest(ctx, fetchReq, reqId)
|
profile.logRequest(ctx, fetchReq, reqId)
|
||||||
|
|
||||||
// Async stack traces are not supported everywhere yet, so we create our own.
|
const res = await fetch(url, req)
|
||||||
const err = new Error()
|
|
||||||
err.isHafasError = true // todo: rename to `isHafasClientError`
|
|
||||||
err.request = req.body // todo: commit as bugfix
|
|
||||||
err.url = url
|
|
||||||
captureStackTrace(err)
|
|
||||||
|
|
||||||
return fetch(fetchReq)
|
// Async stack traces are not supported everywhere yet, so we create our own.
|
||||||
.then((res) => {
|
const errProps = {
|
||||||
err.statusCode = res.status
|
isHafasError: true, // todo: rename to `isHafasClientError`
|
||||||
if (!res.ok) {
|
statusCode: res.status,
|
||||||
err.message = res.statusText
|
request: req.body, // todo [breaking]: change to fetchReq
|
||||||
|
url: url,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const err = new Error(res.statusText)
|
||||||
|
Object.assign(err, errProps)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
|
||||||
|
let cType = res.headers.get('content-type')
|
||||||
|
if (cType) {
|
||||||
|
const {type} = parseContentType(cType)
|
||||||
|
if (type !== 'application/json') {
|
||||||
|
const err = new Error('invalid response content-type: ' + cType)
|
||||||
|
err.response = res
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let cType = res.headers.get('content-type')
|
const body = await res.text()
|
||||||
if (cType) {
|
profile.logResponse(ctx, res, body, reqId)
|
||||||
const {type} = parseContentType(cType)
|
|
||||||
if (type !== 'application/json') {
|
const b = JSON.parse(body)
|
||||||
const err = new Error('invalid response content-type: ' + cType)
|
if (b.err) errProps.hafasErrorCode = b.err
|
||||||
err.response = res
|
if (b.errTxt) errProps.hafasErrorMessage = b.errTxt
|
||||||
throw err
|
if (b.id) errProps.responseId = b.id
|
||||||
}
|
if (b.err && b.err !== 'OK') {
|
||||||
|
const err = new Error(b.errTxt || b.err)
|
||||||
|
Object.assign(err, errProps)
|
||||||
|
if (b.err in byErrorCode) {
|
||||||
|
Object.assign(err, byErrorCode[b.err])
|
||||||
}
|
}
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
if (!b.svcResL || !b.svcResL[0]) {
|
||||||
|
const err = new Error('invalid/unsupported response structure')
|
||||||
|
Object.assign(err, errProps)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
if (b.svcResL[0].err !== 'OK') {
|
||||||
|
const err = new Error(b.svcResL[0].errTxt || b.svcResL[0].err)
|
||||||
|
Object.assign(err, errProps)
|
||||||
|
if (b.svcResL[0].err in byErrorCode) {
|
||||||
|
Object.assign(err, byErrorCode[b.svcResL[0].err])
|
||||||
|
}
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
|
||||||
return res.text()
|
const svcRes = b.svcResL[0].res
|
||||||
.then((body) => {
|
return {
|
||||||
profile.logResponse(ctx, res, body, reqId)
|
res: svcRes,
|
||||||
const b = JSON.parse(body)
|
common: profile.parseCommon({...ctx, res: svcRes}),
|
||||||
|
}
|
||||||
if (b.err && b.err !== 'OK') {
|
|
||||||
addErrorInfo(err, b.err, b.errTxt, b.id)
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
if (!b.svcResL || !b.svcResL[0]) {
|
|
||||||
err.message = 'invalid response'
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
if (b.svcResL[0].err !== 'OK') {
|
|
||||||
addErrorInfo(err, b.svcResL[0].err, b.svcResL[0].errTxt, b.id)
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
|
|
||||||
const svcRes = b.svcResL[0].res
|
|
||||||
return {
|
|
||||||
res: svcRes,
|
|
||||||
common: profile.parseCommon({...ctx, res: svcRes}),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = request
|
module.exports = request
|
||||||
|
|
|
@ -46,7 +46,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@derhuerst/br2nl": "^1.0.0",
|
"@derhuerst/br2nl": "^1.0.0",
|
||||||
"@derhuerst/round-robin-scheduler": "^1.0.4",
|
"@derhuerst/round-robin-scheduler": "^1.0.4",
|
||||||
"capture-stack-trace": "^1.0.0",
|
|
||||||
"content-type": "^1.0.4",
|
"content-type": "^1.0.4",
|
||||||
"create-hash": "^1.2.0",
|
"create-hash": "^1.2.0",
|
||||||
"fetch-ponyfill": "^7.0.0",
|
"fetch-ponyfill": "^7.0.0",
|
||||||
|
|
Loading…
Add table
Reference in a new issue