Responses
A ResponseRule
allows you to write assertions around the response status codes in your API Specification.
new ResponseRule({
name: "prevent response removal",
rule: (responseAssertions) => {
responseAssertions.removed("not remove response", () => {
throw new RuleError({
message: "cannot remove an response",
});
});
},
});
new ResponseRule(options)
The following table describes the options object.
property | description | required | type |
---|---|---|---|
name | the name of the rule | yes | string |
matches | A function used to determine when this Rule should be applied. Return true to indicate this Rule should run. | no | (response: Response, ruleContext: RuleContext) => boolean |
docsLink | A link to the documentation for this ruleset. This will be used to show the user on a rule error. If there is a more specific docsLink (e.g. on a nested Rule), the more specific docsLink will be shown) | no | string |
rule | A function to define assertions for a specification. | yes | (responseAssertions: ResponseAssertions, ruleContext: RuleContext) => void |
matches
matches
is invoked with a Response
and RuleContext
.
Example:
new ResponseRule({
...,
// only matches responses with content type 'application/json' and status code 201 in post operations
matches: (response, ruleContext) => (
ruleContext.operation.method === 'post' &&
response.statusCode === '201'
),
...
});
responseAssertions
responseAssertions is used to define response rules.
responseAssertions[lifecycle](assertion)
new ResponseRule({
...,
rule: (responseAssertions) => {
// lifecycle rules that are available are added, changed, addedOrChanged, requirement and removed
responseAssertions.added('contain description', (response) => {
if (!response.value.description) {
throw new RuleError({
message: 'response must contain a description',
});
}
});
},
});
responseAssertions also includes a number of common helper functions. These are invoked by defining a lifecycle trigger, and then the helper function. e.g. responseAssertions[lifecycle].helperFunction()
.
The helper functions that are included are:
- hasResponseHeaderMatching
All of these helper functions can be inverted by prefixing with .not
.
e.g. responseAssertions.added.not.hasResponseHeaderMatching('X-Application', { description: Matchers.string })
hasResponseHeaderMatching
responseAssertions[lifecycle].hasResponseHeaderMatching(headerName, shape)
Expects the operation to match a shape. The default behavior is to do a partial match.
import { Matchers } from '@useoptic/rulesets-base';
new ResponseRule({
...,
rule: (responseAssertions) => {
responseAssertions.added.hasResponseHeaderMatching('X-Application', {
description: Matchers.string
});
},
});
responseAssertions.header
responseAssertions.header is used to define response header rules.
responseAssertions.header[lifecycle](assertion)
new ResponseRule({
...,
rule: (responseAssertions) => {
// lifecycle rules that are available are added, changed, addedOrChanged, requirement and removed
responseAssertions.header.added('contains a description', (header) => {
if (!header.value.description) {
throw new RuleError({
message: 'header must contain a description',
});
}
});
},
});
Response Body
A ResponseBodyRule allows you to write assertions about the shape of the response bodies:
new ResponseBodyRule({
name: "prevent response body removal",
rule: (responseBodyAssertions) => {
responseBodyAssertions.body.removed("not remove response", () => {
throw new RuleError({
message: "cannot remove an response",
});
});
},
});
new ResponseBodyRule(options)
The following table describes the options object.
property | description | required | type |
---|---|---|---|
name | the name of the rule | yes | string |
matches | A function used to determine when this Rule should be applied. Return true to indicate this Rule should run. | no | (response: ResponseBody, ruleContext: RuleContext) => boolean |
docsLink | A link to the documentation for this ruleset. This will be used to show the user on a rule error. If there is a more specific docsLink (e.g. on a nested Rule), the more specific docsLink will be shown) | no | string |
rule | A function to define assertions for a specification. | yes | (responseBodyAssertions: ResponseBodyAssertions, ruleContext: RuleContext) => void |
matches
matches
is invoked with a ResponseBody
and RuleContext
.
Example:
new ResponseBodyRule({
...,
// only matches responses with content type 'application/json' and status code 201 in post operations
matches: (response, ruleContext) => (
ruleContext.operation.method === 'post' &&
response.contentType === 'application/json' &&
response.statusCode === '201'
),
...
});
responseBodyAssertions.body
responseBodyAssertions.body is used to define response rules.
responseBodyAssertions.body[lifecycle](assertion)
new ResponseBodyRule({
...,
rule: (responseBodyAssertions) => {
// lifecycle rules that are available are added, changed, addedOrChanged, requirement and removed
responseBodyAssertions.body.added('contain description', (response) => {
if (!response.value.description) {
throw new RuleError({
message: 'response bodies must contain a description',
});
}
});
},
});
responseBodyAssertions.body also includes a number of common helper functions. These are invoked by defining a lifecycle trigger, and then the helper function. e.g. responseBodyAssertions.body[lifecycle].helperFunction()
.
The helper functions that are included are:
- matches
- matchesOneOf
All of these helper functions can be inverted by prefixing with .not
.
e.g. responseBodyAssertions.body.added.not.matches({ schema: { type: 'array' } })
matches
responseBodyAssertions.body[lifecycle].matches(shape)
Expects the operation to match a shape. The default behavior is to do a partial match.
import { Matchers } from '@useoptic/rulesets-base';
new ResponseBodyRule({
...,
rule: (responseBodyAssertions) => {
responseBodyAssertions.body.added.matches({
description: Matchers.string
});
},
});
matchesOneOf
responseBodyAssertions.body[lifecycle].matches(shape)
Expects the operation to match one of an array of shapes. The default behavior is to do a partial match.
import { Matchers } from '@useoptic/rulesets-base';
new ResponseBodyRule({
...,
rule: (responseBodyAssertions) => {
responseBodyAssertions.body.added.matches([
{ description: Matchers.string },
{ summary: Matchers.string },
]);
},
});
responseBodyAssertions.property
responseBodyAssertions.property is used to define response body property rules. You can write a rule about all properties (including request body properties) using the PropertyRule.
responseBodyAssertions.property[lifecycle](assertion)
new ResponseBodyRule({
...,
rule: (responseBodyAssertions) => {
// lifecycle rules that are available are added, changed, addedOrChanged, requirement and removed
responseBodyAssertions.property.added('contains a type', (property) => {
if (!property.value.type) {
throw new RuleError({
message: 'properties must contain a type',
});
}
});
},
});
responseBodyAssertions.schema
responseBodyAssertions.schema is used to define rules on any schema in a response body. Schemas can exist on the root response body, as an object field, array item and on polymorphic types (oneOf, anyOf, allOf).
responseBodyAssertions.schema[lifecycle](assertion)
new ResponseBodyRule({
...,
rule: (responseBodyAssertions) => {
// lifecycle rules that are available are added, changed, addedOrChanged, requirement and removed
responseBodyAssertions.schema.added('contains a type', (schema) => {
if (!schema.value.flatSchema.type) {
throw new RuleError({
message: 'schemas must contain a type',
});
}
// schemas also contain the location of where the schema is located
// Other examples include type === 'oneOf', 'array', etc
if (schema.location.context.type === 'field' && schema.location.context.required) {
// On field types, the context also includes required and key
throw new RuleError({
message: 'cannot add required fields',
});
}
});
},
});