govinfo-link-js
Version:
Access U.S. Government Publishing Office's FDsys (Federal Digital System) content and metadata collections using the govinfo-link-js client of Node.js and Web browsers.
675 lines (575 loc) • 21.4 kB
JavaScript
/**
* govinfo-link-js
* <p>The <strong>govinfo</strong> Link Service provides services for developers and webmasters to access content and metadata on <strong>govinfo</strong>. Current and planned services include a link service, list service, and search service. Please contact <a href=\"https://www.gpo.gov/askgpo/\">askGPO</a> for additional information about current or planned services.</p> <p>The link service is used to create embedded links to content and metadata on <strong>govinfo</strong> and is currently enabled for the collections below. The collection code is listed in parenthesis after each collection name, and the available queries are listed below each collection. More information about each query is provided on the individual collection page.</p>
*
* OpenAPI spec version: 1.0.0
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
*
* Swagger Codegen version: 2.3.1
*
* Do not edit the class manually.
*
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([
'superagent',
'querystring'
], factory)
} else if (typeof module === 'object' && module.exports) {
// CommonJS-like environments that support module.exports, like Node.
module.exports = factory(require('superagent'), require('querystring'))
} else {
// Browser globals (root is window)
if (!root.govinfoLinkService) {
root.govinfoLinkService = {
}
}
root.govinfoLinkService.ApiClient = factory(root.superagent, root.querystring)
}
}(this, (superagent, querystring) => {
/**
* @module ApiClient
* @version 1.0.0
*/
/**
* Manages low level client-server communications, parameter marshalling, etc. There should not be any need for an
* application to use this class directly - the *Api and model classes provide the public API for the service. The
* contents of this file should be regarded as internal but are documented for completeness.
*
* @alias module:ApiClient
* @class
*/
const exports = function () {
/**
* The base URL against which to resolve every API call's (relative) path.
* @type {String}
* @default https://www.govinfo.gov/link
*/
this.basePath = 'https://www.govinfo.gov/link'.replace(/\/+$/, '')
/**
* The authentication methods to be included for all API calls.
* @type {Array.<String>}
*/
this.authentications = {
}
/**
* The default HTTP headers to be included for all API calls.
* @type {Array.<String>}
* @default {}
*/
this.defaultHeaders = {
}
/**
* The default HTTP timeout for all API calls.
* @type {Number}
* @default 60000
*/
this.timeout = 60000
/**
* If set to false an additional timestamp parameter is added to all API GET calls to
* prevent browser caching
* @type {Boolean}
* @default true
*/
this.cache = true
/**
* If set to true, the client will save the cookies from each server
* response, and return them in the next request.
* @default false
*/
this.enableCookies = false
/*
* Used to save and return cookies in a node.js (non-browser) setting,
* if this.enableCookies is set to true.
*/
if (typeof window === 'undefined') {
this.agent = new superagent.agent()
}
/*
* Allow user to override superagent agent
*/
this.requestAgent = null
}
/**
* Returns a string representation for an actual parameter.
*
* @param param - The actual parameter.
* @returns {string} The string representation of <code>param</code>.
*/
exports.prototype.paramToString = function (param) {
if (param == undefined || param == null) {
return ''
}
if (param instanceof Date) {
return param.toJSON()
}
return param.toString()
}
/**
* Builds full URL by appending the given path to the base URL and replacing path parameter place-holders with parameter values.
* NOTE: Query parameters are not handled here.
*
* @param {string} path - The path to append to the base URL.
* @param {Object} pathParams - The parameter values to append.
* @returns {string} The encoded path with parameter values substituted.
*/
exports.prototype.buildUrl = function (path, pathParams) {
if (!path.match(/^\//)) {
path = `/${path}`
}
let url = this.basePath + path
const _this = this
url = url.replace(/\{([\w-]+)\}/g, (fullMatch, key) => {
let value
if (pathParams.hasOwnProperty(key)) {
value = _this.paramToString(pathParams[key])
} else {
value = fullMatch
}
return encodeURIComponent(value)
})
return url
}
/**
* Checks whether the given content type represents JSON.<br>
* JSON content type examples:<br>
* <ul>
* <li>application/json</li>
* <li>application/json; charset=UTF8</li>
* <li>APPLICATION/JSON</li>
* </ul>.
*
* @param {string} contentType - The MIME content type to check.
* @returns {boolean} <code>true</code> if <code>contentType</code> represents JSON, otherwise <code>false</code>.
*/
exports.prototype.isJsonMime = function (contentType) {
return Boolean(contentType != null && contentType.match(/^application\/json(;.*)?$/i))
}
/**
* Chooses a content type from the given array, with JSON preferred; i.e. Return JSON if included, otherwise return the first.
*
* @param {Array.<String>} contentTypes
* @returns {string} The chosen content type, preferring JSON.
*/
exports.prototype.jsonPreferredMime = function (contentTypes) {
for (let i = 0; i < contentTypes.length; i++) {
if (this.isJsonMime(contentTypes[i])) {
return contentTypes[i]
}
}
return contentTypes[0]
}
/**
* Checks whether the given parameter value represents file-like content.
*
* @param param - The parameter to check.
* @returns {boolean} <code>true</code> if <code>param</code> represents a file.
*/
exports.prototype.isFileParam = function (param) {
// Fs.ReadStream in Node.js and Electron (but not in runtime like browserify)
if (typeof require === 'function') {
let fs
try {
fs = require('fs')
} catch (err) {}
if (fs && fs.ReadStream && param instanceof fs.ReadStream) {
return true
}
}
// Buffer in Node.js
if (typeof Buffer === 'function' && param instanceof Buffer) {
return true
}
// Blob in browser
if (typeof Blob === 'function' && param instanceof Blob) {
return true
}
// File in browser (it seems File object is also instance of Blob, but keep this for safe)
if (typeof File === 'function' && param instanceof File) {
return true
}
return false
}
/**
* Normalizes parameter values:
* <ul>
* <li>remove nils</li>
* <li>keep files and arrays</li>
* <li>format to string with `paramToString` for other cases</li>
* </ul>.
*
* @param {Object.<String, Object>} params - The parameters as object properties.
* @returns {Object.<String, Object>} Normalized parameters.
*/
exports.prototype.normalizeParams = function (params) {
const newParams = {
}
for (const key in params) {
if (params.hasOwnProperty(key) && params[key] != undefined && params[key] != null) {
const value = params[key]
if (this.isFileParam(value) || Array.isArray(value)) {
newParams[key] = value
} else {
newParams[key] = this.paramToString(value)
}
}
}
return newParams
}
/**
* Enumeration of collection format separator strategies.
* @enum {String}
* @readonly
*/
exports.CollectionFormatEnum = {
/**
* Comma-separated values. Value: <code>csv</code>
* @const
*/
'CSV': ',',
/**
* Space-separated values. Value: <code>ssv</code>
* @const
*/
'SSV': ' ',
/**
* Tab-separated values. Value: <code>tsv</code>
* @const
*/
'TSV': '\t',
/**
* Pipe(|)-separated values. Value: <code>pipes</code>
* @const
*/
'PIPES': '|',
/**
* Native array. Value: <code>multi</code>
* @const
*/
'MULTI': 'multi'
}
/**
* Builds a string representation of an array-type actual parameter, according to the given collection format.
*
* @param {Array} param - An array parameter.
* @param {module:ApiClient.CollectionFormatEnum} collectionFormat - The array element separator strategy.
* @returns {String|Array} A string representation of the supplied collection, using the specified delimiter. Returns
* <code>param</code> as is if <code>collectionFormat</code> is <code>multi</code>.
*/
exports.prototype.buildCollectionParam = function buildCollectionParam (param, collectionFormat) {
if (param == null) {
return null
}
switch (collectionFormat) {
case 'csv':
return param.map(this.paramToString).join(',')
case 'ssv':
return param.map(this.paramToString).join(' ')
case 'tsv':
return param.map(this.paramToString).join('\t')
case 'pipes':
return param.map(this.paramToString).join('|')
case 'multi':
// Return the array directly as SuperAgent will handle it as expected
return param.map(this.paramToString)
default:
throw new Error(`Unknown collection format: ${collectionFormat}`)
}
}
/**
* Applies authentication headers to the request.
*
* @param {Object} request - The request object created by a <code>superagent()</code> call.
* @param {Array.<String>} authNames - An array of authentication method names.
*/
exports.prototype.applyAuthToRequest = function (request, authNames) {
const _this = this
authNames.forEach((authName) => {
const auth = _this.authentications[authName]
switch (auth.type) {
case 'basic':
if (auth.username || auth.password) {
request.auth(auth.username || '', auth.password || '')
}
break
case 'apiKey':
if (auth.apiKey) {
const data = {
}
if (auth.apiKeyPrefix) {
data[auth.name] = `${auth.apiKeyPrefix} ${auth.apiKey}`
} else {
data[auth.name] = auth.apiKey
}
if (auth.in === 'header') {
request.set(data)
} else {
request.query(data)
}
}
break
case 'oauth2':
if (auth.accessToken) {
request.set({
'Authorization': `Bearer ${auth.accessToken}`
})
}
break
default:
throw new Error(`Unknown authentication type: ${auth.type}`)
}
})
}
/**
* Deserializes an HTTP response body into a value of the specified type.
*
* @param {Object} response - A SuperAgent response object.
* @param {(String|Array.<String>|Object.<String, Object>|Function)} returnType The type to return. Pass a string for simple types
* or the constructor function for a complex type. Pass an array containing the type name to return an array of that type. To
* return an object, pass an object with one property whose name is the key type and whose value is the corresponding value type:
* all properties on <code>data<code> will be converted to this type.
* @returns A value of the specified type.
*/
exports.prototype.deserialize = function deserialize (response, returnType) {
if (response == null || returnType == null || response.status == 204) {
return null
}
/*
* Rely on SuperAgent for parsing response body.
* See http://visionmedia.github.io/superagent/#parsing-response-bodies
*/
let data = response.body
if (data == null || (typeof data === 'object' && typeof data.length === 'undefined' && !Object.keys(data).length)) {
// SuperAgent does not always produce a body; use the unparsed response as a fallback
data = response.text
}
return exports.convertToType(data, returnType)
}
/**
* Callback function to receive the result of the operation.
* @callback module:ApiClient~callApiCallback
* @param {String} error Error message, if any.
* @param data The data returned by the service call.
* @param {String} response The complete HTTP response.
*/
/**
* Invokes the REST service using the supplied settings and parameters.
* @param {string} path - The base URL to invoke.
* @param {String} httpMethod - The HTTP method to use.
* @param {Object.<String, String>} pathParams - A map of path parameters and their values.
* @param {Object.<String, Object>} queryParams - A map of query parameters and their values.
* @param {Object.<String, Object>} collectionQueryParams - A map of collection query parameters and their values.
* @param {Object.<String, Object>} headerParams - A map of header parameters and their values.
* @param {Object.<String, Object>} formParams - A map of form parameters and their values.
* @param {Object} bodyParam - The value to pass as the request body.
* @param {Array.<String>} authNames - An array of authentication type names.
* @param {Array.<String>} contentTypes - An array of request MIME types.
* @param {Array.<String>} accepts - An array of acceptable response MIME types.
* @param {(String|Array|ObjectFunction)} returnType The required type to return; can be a string for simple types or the
* constructor for a complex type.
* @param {module:ApiClient~callApiCallback} callback - The callback function.
* @returns {Object} The SuperAgent request object.
*/
exports.prototype.callApi = function callApi (
path, httpMethod, pathParams,
queryParams, collectionQueryParams, headerParams, formParams, bodyParam, authNames, contentTypes, accepts,
returnType, callback
) {
const _this = this
const url = this.buildUrl(path, pathParams)
const request = superagent(httpMethod, url)
// Apply authentications
this.applyAuthToRequest(request, authNames)
// Set collection query parameters
for (const key in collectionQueryParams) {
if (collectionQueryParams.hasOwnProperty(key)) {
const param = collectionQueryParams[key]
if (param.collectionFormat === 'csv') {
/*
* SuperAgent normally percent-encodes all reserved characters in a query parameter. However,
* commas are used as delimiters for the 'csv' collectionFormat so they must not be encoded. We
* must therefore construct and encode 'csv' collection query parameters manually.
*/
if (param.value != null) {
const value = param.value.map(this.paramToString).map((x) => encodeURIComponent(x))
.join(',')
request.query(`${encodeURIComponent(key)}=${value}`)
}
} else {
// All other collection query parameters should be treated as ordinary query parameters.
queryParams[key] = this.buildCollectionParam(param.value, param.collectionFormat)
}
}
}
// Set query parameters
if (httpMethod.toUpperCase() === 'GET' && this.cache === false) {
queryParams._ = new Date().getTime()
}
request.query(this.normalizeParams(queryParams))
// Set header parameters
request.set(this.defaultHeaders).set(this.normalizeParams(headerParams))
// Set requestAgent if it is set by user
if (this.requestAgent) {
request.agent(this.requestAgent)
}
// Set request timeout
request.timeout(this.timeout)
const contentType = this.jsonPreferredMime(contentTypes)
if (contentType) {
// Issue with superagent and multipart/form-data (https://github.com/visionmedia/superagent/issues/746)
if (contentType != 'multipart/form-data') {
request.type(contentType)
}
} else if (!request.header['Content-Type']) {
request.type('application/json')
}
if (contentType === 'application/x-www-form-urlencoded') {
request.send(querystring.stringify(this.normalizeParams(formParams)))
} else if (contentType == 'multipart/form-data') {
const _formParams = this.normalizeParams(formParams)
for (const key in _formParams) {
if (_formParams.hasOwnProperty(key)) {
if (this.isFileParam(_formParams[key])) {
// File field
request.attach(key, _formParams[key])
} else {
request.field(key, _formParams[key])
}
}
}
} else if (bodyParam) {
request.send(bodyParam)
}
const accept = this.jsonPreferredMime(accepts)
if (accept) {
request.accept(accept)
}
if (returnType === 'Blob') {
request.responseType('blob')
} else if (returnType === 'String') {
request.responseType('string')
}
// Attach previously saved cookies, if enabled
if (this.enableCookies) {
if (typeof window === 'undefined') {
this.agent.attachCookies(request)
} else {
request.withCredentials()
}
}
request.end((error, response) => {
if (callback) {
let data = null
if (!error) {
try {
data = _this.deserialize(response, returnType)
if (_this.enableCookies && typeof window === 'undefined') {
_this.agent.saveCookies(response)
}
} catch (err) {
error = err
}
}
callback(error, data, response)
}
})
return request
}
/**
* Parses an ISO-8601 string representation of a date value.
*
* @param {string} str - The date value as a string.
* @returns {Date} The parsed date object.
*/
exports.parseDate = function (str) {
return new Date(str.replace(/T/i, ' '))
}
/**
* Converts a value to the specified type.
*
* @param {(String|Object)} data - The data to convert, as a string or object.
* @param {(String|Array.<String>|Object.<String, Object>|Function)} type The type to return. Pass a string for simple types
* or the constructor function for a complex type. Pass an array containing the type name to return an array of that type. To
* return an object, pass an object with one property whose name is the key type and whose value is the corresponding value type:
* all properties on <code>data<code> will be converted to this type.
* @returns An instance of the specified type or null or undefined if data is null or undefined.
*/
exports.convertToType = function (data, type) {
if (data === null || data === undefined) return data
switch (type) {
case 'Boolean':
return Boolean(data)
case 'Integer':
return parseInt(data, 10)
case 'Number':
return parseFloat(data)
case 'String':
return String(data)
case 'Date':
return this.parseDate(String(data))
case 'Blob':
return data
default:
if (type === Object) {
// Generic object, return directly
return data
} else if (typeof type === 'function') {
// For model type like: User
return type.constructFromObject(data)
} else if (Array.isArray(type)) {
// For array type like: ['String']
const itemType = type[0]
return data.map((item) => exports.convertToType(item, itemType))
} else if (typeof type === 'object') {
// For plain object type like: {'String': 'Integer'}
let keyType, valueType
for (const k in type) {
if (type.hasOwnProperty(k)) {
keyType = k
valueType = type[k]
break
}
}
const result = {
}
for (const k in data) {
if (data.hasOwnProperty(k)) {
const key = exports.convertToType(k, keyType)
const value = exports.convertToType(data[k], valueType)
result[key] = value
}
}
return result
}
// For unknown type, return the data directly
return data
}
}
/**
* Constructs a new map or array model from REST data.
*
* @param data - {Object|Array} The REST data.
* @param obj - {Object|Array} The target object or array.
*/
exports.constructFromObject = function (data, obj, itemType) {
if (Array.isArray(data)) {
for (let i = 0; i < data.length; i++) {
if (data.hasOwnProperty(i)) obj[i] = exports.convertToType(data[i], itemType)
}
} else {
for (const k in data) {
if (data.hasOwnProperty(k)) obj[k] = exports.convertToType(data[k], itemType)
}
}
}
/**
* The default API client implementation.
* @type {module:ApiClient}
*/
exports.instance = new exports()
return exports
}))