UNPKG

@superhero/oas

Version:

OpenAPI Specification (OAS) router

187 lines (156 loc) 4.96 kB
import ComponentsAbstraction from './abstraction.js' /** * @memberof Oas.Components */ export default class Parameters extends ComponentsAbstraction { validParameterAttributes = [ 'name', 'in', 'required', 'description', 'deprecated', 'allowEmptyValue', 'schema', 'style', 'explode', 'examples', 'example', 'allowReserved', 'nullable', 'default', '$ref' ] constructor(schemas) { super() this.schemas = schemas } conform(component, request) { const value = this.getParameterValue(component, request) return request.param[component.name] = value ?? request.param[component.name] } getParameterValue(parameter, request) { if(parameter.$ref) { return this.conformRef(parameter.$ref, request) } let instance = this.extractValueFromRequest(parameter, request) if('schema' in parameter) { instance = this.schemas.conform(parameter.schema, instance, true) } if('default' in parameter && undefined === instance) { instance = parameter.default } if(parameter.nullable && null === instance) { return instance } if(undefined === instance &&(parameter.required || 'path' === parameter.in)) { const error = new Error(`The parameter "${parameter.name}" is required`) error.code = 'E_OAS_INVALID_INSTANCE' throw error } if(false === !!parameter.allowEmptyValue && '' === instance) { const error = new Error(`The parameter ${parameter.name} is not allowed to be empty`) error.code = 'E_OAS_INVALID_INSTANCE' error.cause = 'The parameter allowEmptyValue attribute is false and the parameter value is empty' throw error } return instance } extractValueFromRequest(parameter, request) { switch(parameter.in) { case 'path' : return parameter.explode ? request.param[parameter.name]?.split(',') : request.param[parameter.name] case 'query' : return parameter.explode ? request.url.searchParams.getAll(parameter.name) : request.url.searchParams.get(parameter.name) ?? undefined case 'header' : return parameter.explode ? request.headers[parameter.name]?.split(',') : request.headers[parameter.name] } } validateRefPointer(pointer) { super.validateRefPointer(pointer) if(false === pointer.startsWith('/components/parameters/')) { const error = new Error(`The ref pointer "${pointer}" must point to a parameters component`) error.code = 'E_OAS_INVALID_SPECIFICATION' throw error } } validateComponent(component) { const componentType = Object.prototype.toString.call(component) if('[object Array]' !== componentType) { const error = new Error(`Invalid component type ${componentType}`) error.code = 'E_OAS_INVALID_SPECIFICATION' error.cause = new Error('The component type must be an [object Array]') throw error } for(const parameter of component) { this.validateParameterComponent(parameter) } } validateParameterComponent(parameter) { const parameterType = Object.prototype.toString.call(parameter) if('[object Object]' !== parameterType) { const error = new Error(`Invalid parameter type ${parameterType}`) error.code = 'E_OAS_INVALID_SPECIFICATION' error.cause = new Error('The parameter type must be an [object Object]') throw error } this.validateComponentRef(parameter) if(parameter.$ref) { // The $ref attribute is the only // attribute allowed when present. return } if(false === 'name' in parameter) { const error = new Error('The "name" attribute is required') error.code = 'E_OAS_INVALID_SPECIFICATION' throw error } if(false === 'in' in parameter) { const error = new Error('The "in" attribute is required') error.code = 'E_OAS_INVALID_SPECIFICATION' throw error } if(false === ['path', 'query', 'header', /*'cookie'*/].includes(parameter.in)) { const error = new Error(`Invalid "in" attribute ${parameter.in}`) error.code = 'E_OAS_INVALID_SPECIFICATION' throw error } if('query' !== parameter.in && 'allowEmptyValue' in parameter) { const error = new Error('The "allowEmptyValue" attribute is only valid for query parameters') error.code = 'E_OAS_UNSUPORTED_SPECIFICATION' throw error } if('allowReserved' in parameter) { const error = new Error('The "allowReserved" attribute is not supported in this implementation') error.code = 'E_OAS_UNSUPORTED_SPECIFICATION' throw error } if('style' in parameter) { const error = new Error('The "style" attribute is not supported in this implementation') error.code = 'E_OAS_UNSUPORTED_SPECIFICATION' throw error } } }