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