Files
shields/core/base-service/base-xml.js
T
chris48sandGitHub 14892e3943 Implement a pattern for dealing with upstream APIs which are slow on the first hit; affects [endpoint] (#9233)
* allow serviceData to override cacheSeconds with a longer value

* prevent [endpoint] json cacheSeconds property exceeding service default

* allow ShieldsRuntimeError to specify a cacheSeconds property

By default error responses use the cacheLength of
the service class throwing the error.

This allows error to tell the handling layer the maxAge
that should be set on the error badge response.

* add customExceptions param

This

1. allows us to specify custom properties to pass to the exception
   constructor if we throw any of the standard got errors
   e.g: `ETIMEDOUT`, `ECONNRESET`, etc
2. uses a custom `cacheSeconds` property (if set on the exception)
   to set the response maxAge

* customExceptions --> systemErrors

* errorMessages --> httpErrors
2023-06-13 21:08:43 +01:00

79 lines
2.9 KiB
JavaScript

/**
* @module
*/
// See available emoji at http://emoji.muan.co/
import emojic from 'emojic'
import { XMLParser, XMLValidator } from 'fast-xml-parser'
import BaseService from './base.js'
import trace from './trace.js'
import { InvalidResponse } from './errors.js'
/**
* Services which query a XML endpoint should extend BaseXmlService
*
* @abstract
*/
class BaseXmlService extends BaseService {
/**
* Request data from an upstream API serving XML,
* parse it and validate against a schema
*
* @param {object} attrs Refer to individual attrs
* @param {Joi} attrs.schema Joi schema to validate the response against
* @param {string} attrs.url URL to request
* @param {object} [attrs.options={}] Options to pass to got. See
* [documentation](https://github.com/sindresorhus/got/blob/main/documentation/2-options.md)
* @param {object} [attrs.httpErrors={}] Key-value map of status codes
* and custom error messages e.g: `{ 404: 'package not found' }`.
* This can be used to extend or override the
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
* @param {object} [attrs.systemErrors={}] Key-value map of got network exception codes
* and an object of params to pass when we construct an Inaccessible exception object
* e.g: `{ ECONNRESET: { prettyMessage: 'connection reset' } }`.
* See {@link https://github.com/sindresorhus/got/blob/main/documentation/7-retry.md#errorcodes got error codes}
* for allowed keys
* and {@link module:core/base-service/errors~RuntimeErrorProps} for allowed values
* @param {object} [attrs.parserOptions={}] Options to pass to fast-xml-parser. See
* [documentation](https://github.com/NaturalIntelligence/fast-xml-parser#xml-to-json)
* @returns {object} Parsed response
* @see https://github.com/sindresorhus/got/blob/main/documentation/2-options.md
* @see https://github.com/NaturalIntelligence/fast-xml-parser#xml-to-json
*/
async _requestXml({
schema,
url,
options = {},
httpErrors = {},
systemErrors = {},
parserOptions = {},
}) {
const logTrace = (...args) => trace.logTrace('fetch', ...args)
const mergedOptions = {
...{ headers: { Accept: 'application/xml, text/xml' } },
...options,
}
const { buffer } = await this._request({
url,
options: mergedOptions,
httpErrors,
systemErrors,
})
const validateResult = XMLValidator.validate(buffer)
if (validateResult !== true) {
throw new InvalidResponse({
prettyMessage: 'unparseable xml response',
underlyingError: validateResult.err,
})
}
const parser = new XMLParser(parserOptions)
const xml = parser.parse(buffer)
logTrace(emojic.dart, 'Response XML (before validation)', xml, {
deep: true,
})
return this.constructor._validate(xml, schema)
}
}
export default BaseXmlService