Operation
An OperationRule
allows you to write assertions around Operations in your API Specification.
new OperationRule({
name: "prevent operation removal",
rule: (operationAssertions) => {
operationAssertions.removed("not remove operation", () => {
throw new RuleError({
message: "cannot remove an operation",
});
});
},
});
new OperationRule(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 | (operation: Operation, 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 (i.e. on a nested Rule), the more specific docsLink will be shown) | no | string |
rule | A function to define assertions for a specification. | yes | (operationAssertions: OperationAssertions, ruleContext: RuleContext) => void |
matches
matches
is invoked with an Operation
and RuleContext
objects. The Operations
object corresponds to the Operation
that this rule would run on. The RuleContext
object contains details about the location in the specification. Return a boolean to indicate whether this rule should be run on the Operation
provided.
Example:
const has201StatusCode = new OperationRule({
name: "Has 201 status codes",
// only matches post operations
matches: (operation, ruleContext) => operation.method === "post",
rule: (operationAssertions) => {
operationAssertions.requirement.hasResponses([{ statusCode: "201" }]);
},
});
operationAssertions
allows you to attach a rule to the operation's lifecycle. A requirement
rule always runs, and added
, changed,
removed,
addedOrChangedrules will run depending on what changes you have made to the spec. Throwing a
RuleError` from inside an assertion represents a failure.
new OperationRule({
...,
rule: (operationAssertions) => {
// lifecycle rules that are available are added, changed, addedOrChanged, requirement and removed
operationAssertions.added('contain summary', (operation) => {
if (!operation.value.summary) {
throw new RuleError({
message: 'operations must contain a summary',
});
}
});
},
});
operationAssertion
also includes a number of common helper functions. These are invoked by defining a lifecycle trigger, and then the helper function. i.e. operationAssertions[lifecycle].helperFunction()
.
The helper functions that are included are:
- hasQueryParameterMatching
- hasPathParameterMatching
- hasHeaderParameterMatching
- hasCookieParameterMatching
- hasRequests
- hasResponses
- matches
- matchesOneOf
All of these helper functions can be inverted by prefixing with .not
.
i.e. operationAssertions.added.not.hasRequests([{contentType: 'application/json'}])
hasQueryParameterMatching
operationAssertions[lifecycle].hasQueryParameterMatching(parameter)
Looks for a query parameter in the operation that has a partial match with parameter. Passes if a partial match is found, fails if a partial match is not found.
new OperationRule({
...,
rule: (operationAssertions) => {
operationAssertions.added.hasQueryParameterMatching({
name: 'version'
});
// This will match a query parameter with the shape `{ name: 'version' }`
// query parameters with more keys will still be matched
},
});
hasPathParameterMatching
operationAssertions[lifecycle].hasPathParameterMatching(parameter)
Looks for a path parameter in the operation that has a partial match with parameter. Passes if a partial match is found, fails if a partial match is not found.
new OperationRule({
...,
rule: (operationAssertions) => {
operationAssertions.added.hasPathParameterMatching({
name: 'userId'
});
// This will match a path parameter with the shape `{ name: 'userId' }`
// path parameters with more keys will still be matched
},
});
hasHeaderParameterMatching
operationAssertions[lifecycle].hasHeaderParameterMatching(parameter)
Looks for a header parameter in the operation that has a partial match with parameter. Passes if a partial match is found, fails if a partial match is not found.
new OperationRule({
...,
rule: (operationAssertions) => {
operationAssertions.added.hasHeaderParameterMatching({
name: 'X-Authorization'
});
// This will match a header parameter with the shape `{ name: 'X-Authorization' }`
// header parameters with more keys will still be matched
},
});
hasCookieParameterMatching
operationAssertions[lifecycle].hasCookieParameterMatching(parameter)
Looks for a cookie parameter in the operation that has a partial match with parameter. Passes if a partial match is found, fails if a partial match is not found.
new OperationRule({
...,
rule: (operationAssertions) => {
operationAssertions.added.hasCookieParameterMatching({
name: 'version'
});
// This will match a cookie parameter with the shape `{ name: 'version' }`
// cookie parameters with more keys will still be matched
},
});
hasRequests
operationAssertions[lifecycle].hasRequests(requests)
Looks for an array of requests with a content type in the operation. A request has the following shape: { contentType: string }
new OperationRule({
...,
rule: (operationAssertions) => {
// asserts that the operation has both 'application/json' and 'application/xml' request bodies
operationAssertions.added.hasRequests([{
contentType: 'application/json'
}, {
contentType: 'application/xml'
}]);
},
});
hasResponses
operationAssertions[lifecycle].hasResponses(requests)
Looks for an array of responses with a content type in the operation. A response has the following shape: { contentType?: string, statusCode: string }' where
contentType` is optional. If content type is not specified, only the status code will be considered when searching for the request.
new OperationRule({
...,
rule: (operationAssertions) => {
// asserts that the operation has the following responses:
// - response 200 with content 'application/json'
// - response 400
operationAssertions.added.hasResponses([{
contentType: 'application/json',
statusCode: '200'
}, {
statusCode: '400'
}]);
},
});
matches
operationAssertions[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 OperationRule({
...,
rule: (operationAssertions) => {
operationAssertions.added.matches({
description: Matchers.string
});
},
});
matchesOneOf
operationAssertions[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 OperationRule({
...,
rule: (operationAssertions) => {
operationAssertions.added.matches([
{ description: Matchers.string },
{ summary: Matchers.string },
]);
},
});
operationAssertions.queryParameter
operationAssertions.queryParameter is used to define query parameter rules.
operationAssertions.queryParameter[lifecycle](assertion)
new OperationRule({
...,
rule: (operationAssertions) => {
// lifecycle rules that are available are added, changed, addedOrChanged, requirement and removed
operationAssertions.queryParameter.added('not add required query parameter', (queryParameter) => {
if (queryParameter.value.required) {
throw new RuleError({
message: 'cannot add a required query parameter',
});
}
});
},
});
operationAssertions.pathParameter
operationAssertions.pathParameter is used to define path parameter rules.
operationAssertions.pathParameter[lifecycle](assertion)
new OperationRule({
...,
rule: (operationAssertions) => {
// lifecycle rules that are available are added, changed, addedOrChanged, requirement and removed
operationAssertions.pathParameter.requirement('be snake_case', (pathParameter) => {
if (!isSnakeCase(pathParameter.value.name)) {
throw new RuleError({
message: 'path parameter must be snake case',
});
}
});
},
});
operationAssertions.headerParameter
operationAssertions.headerParameter is used to define header parameter rules.
operationAssertions.headerParameter[lifecycle](assertion)
new OperationRule({
...,
rule: (operationAssertions) => {
// lifecycle rules that are available are added, changed, addedOrChanged, requirement and removed
operationAssertions.headerParameter.added('not add required header parameter', (headerParameter) => {
if (headerParameter.value.required) {
throw new RuleError({
message: 'cannot add a required header parameter',
});
}
});
},
});
operationAssertions.cookieParameter
operationAssertions.cookieParameter is used to define cookie parameter rules.
operationAssertions.cookieParameter[lifecycle](assertion)
new OperationRule({
...,
rule: (operationAssertions) => {
// lifecycle rules that are available are added, changed, addedOrChanged, requirement and removed
operationAssertions.cookieParameter.added('not add required cookie parameter', (cookieParameter) => {
if (cookieParameter.value.required) {
throw new RuleError({
message: 'cannot add a required cookie parameter',
});
}
});
},
});