From b144dd5358ae40548ee216422aaf2dfdacaf5029 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Sun, 16 Dec 2018 23:47:36 +0100 Subject: [PATCH] parse & expose error codes --- lib/errors.js | 179 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/request.js | 18 ++++- 2 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 lib/errors.js diff --git a/lib/errors.js b/lib/errors.js new file mode 100644 index 00000000..e0e08097 --- /dev/null +++ b/lib/errors.js @@ -0,0 +1,179 @@ +'use strict' + +const ACCESS_DENIED = 'ACCESS_DENIED' +const INVALID_REQUEST = 'INVALID_REQUEST' +const NOT_FOUND = 'NOT_FOUND' +const SERVER_ERROR = 'SERVER_ERROR' + +// https://gist.github.com/derhuerst/79d49c0f04c1c192a5d15756e5af575f/edit +const byErrorCode = Object.assign(Object.create(null), { + AUTH: { + isClient: true, + code: ACCESS_DENIED, + message: 'invalid or missing authentication data' + }, + R0001: { + isClient: true, + code: INVALID_REQUEST, + message: 'unknown method' + }, + R0002: { + isClient: true, + code: INVALID_REQUEST, + message: 'invalid or missing request parameters' + }, + R0007: { + isServer: true, + code: SERVER_ERROR, + message: 'internal communication error' + }, + R5000: { + isClient: true, + code: ACCESS_DENIED, + message: 'access denied' + }, + S1: { + isServer: true, + code: SERVER_ERROR, + message: 'journeys search: a connection to the backend server couldn\'t be established' + }, + LOCATION: { + isClient: true, + code: INVALID_REQUEST, + message: 'location/stop not found' + }, + H390: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: departure/arrival station replaced' + }, + H410: { + // todo: or is it a client error? + // todo: statusCode? + isServer: true, + code: SERVER_ERROR, + message: 'journeys search: incomplete response due to timetable change' + }, + H455: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: prolonged stop' + }, + H460: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: stop(s) passed multiple times' + }, + H500: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: too many trains, connection is not complete' + }, + H890: { + isClient: true, + code: NOT_FOUND, + message: 'journeys search unsuccessful' + }, + H891: { + isClient: true, + code: NOT_FOUND, + message: 'journeys search: no route found, try with an intermediate stations' + }, + H892: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: query too complex, try less intermediate stations' + }, + H895: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: departure & arrival are too near' + }, + H899: { + // todo: or is it a client error? + // todo: statusCode? + isServer: true, + code: SERVER_ERROR, + message: 'journeys search unsuccessful or incomplete due to timetable change' + }, + H900: { + // todo: or is it a client error? + // todo: statusCode? + isServer: true, + code: SERVER_ERROR, + message: 'journeys search unsuccessful or incomplete due to timetable change' + }, + H9220: { + isClient: true, + code: NOT_FOUND, + message: 'journeys search: no stations found close to the address' + }, + H9230: { + isServer: true, + code: SERVER_ERROR, + message: 'journeys search: an internal error occured' + }, + H9240: { + isClient: true, + code: NOT_FOUND, + message: 'journeys search unsuccessful' + }, + H9250: { + isServer: true, + code: SERVER_ERROR, + message: 'journeys search: leg query interrupted' + }, + H9260: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: unknown departure station' + }, + H9280: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: unknown intermediate station' + }, + H9300: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: unknown arrival station' + }, + H9320: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: the input is incorrect or incomplete' + }, + H9360: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: error in a data field' + }, + H9380: { + isClient: true, + code: INVALID_REQUEST, + message: 'journeys search: departure/arrival/intermediate station defined more than once' + }, + SQ001: { + isServer: true, + code: SERVER_ERROR, + message: 'no departures/arrivals data available' + }, + SQ005: { + isClient: true, + code: NOT_FOUND, + message: 'no trips found' + }, + TI001: { + isServer: true, + code: SERVER_ERROR, + message: 'no trip info available' + } +}) + +module.exports = { + ACCESS_DENIED, + INVALID_REQUEST, + NOT_FOUND, + SERVER_ERROR, + byErrorCode +} diff --git a/lib/request.js b/lib/request.js index edfc4a08..bbb1f58a 100644 --- a/lib/request.js +++ b/lib/request.js @@ -9,6 +9,7 @@ const captureStackTrace = DEV ? require('capture-stack-trace') : () => {} const {stringify} = require('qs') const Promise = require('pinkie-promise') const {fetch} = require('fetch-ponyfill')({Promise}) +const {byErrorCode} = require('./errors') let id try { @@ -26,6 +27,17 @@ const randomizeUserAgent = (userAgent) => { const md5 = input => createHash('md5').update(input).digest() +const addErrorInfo = (err, errorCode, errorText) => { + 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 + } +} + const request = (profile, userAgent, opt, data) => { const body = profile.transformReqBody({ lang: opt.language || 'en', // todo: is it `eng` actually? @@ -72,7 +84,7 @@ const request = (profile, userAgent, opt, data) => { // Async stack traces are not supported everywhere yet, so we create our own. const err = new Error() - err.isHafasError = true + err.isHafasError = true // todo: rename to `isHafasClientError` err.request = body err.url = url captureStackTrace(err) @@ -90,7 +102,7 @@ const request = (profile, userAgent, opt, data) => { if (DEBUG) console.error(JSON.stringify(b)) if (b.err && b.err !== 'OK') { - err.message = b.err + addErrorInfo(err, b.err, b.errTxt) throw err } if (!b.svcResL || !b.svcResL[0]) { @@ -98,7 +110,7 @@ const request = (profile, userAgent, opt, data) => { throw err } if (b.svcResL[0].err !== 'OK') { - err.message = b.svcResL[0].errTxt || b.svcResL[0].err + addErrorInfo(err, b.svcResL[0].err, b.svcResL[0].errTxt) throw err } const d = b.svcResL[0].res