A rest block declares REST resources. A REST resource is the request of an endpoint and method, or one response of an endpoint, method and status, and each one is compared on its own. What holds for every kind of resource is in The contract file.
A request and its responses live together under the same method:
provides: rest: /pets: post: request: NewPet responses: 201: Pet 500: Error
This declares three resources: the request of POST /pets, its 201 response and its 500 response. A break in the 500 does not involve the 201.
The consumer produces a request and the provider reads it; the provider produces a response and the consumer reads it. The reader of a body decides what must be in it (Which side decides).
A report names a REST resource by its method and endpoint, then request or response <status>, as in GET /pets/* response 200 (Resource breaks).
Endpoints#
The endpoint is part of a resource's identity, so a consumer's endpoint matches a provider's only when both are written the same way:
- An endpoint starts with
/and has no empty segment://and/pets//photosare rejected at publish withmalformed path. A;in a segment, as in/pets;v=2, is amalformed pathtoo./alone is the root, a valid endpoint. - A dynamic segment is
*, one per segment, with no name:/pets/*,/owners/*/pets/*. {petId}and partial wildcards such asp*are rejected at publish, not rewritten.:petIdis read as a literal segment that no request path matches, so write*.- A trailing slash is removed:
/pets/is/pets, and a provider that writes both has declared the same resources twice. - The methods are
get,post,put,patchanddelete, in lowercase. Any other key under an endpoint is rejected.
An endpoint copied from an OpenAPI document keeps its named parameter and is rejected:
provides: rest: /pets/{petId}: get: responses: 200: Pet
contract validation failed - petstore_api.yaml: invalid endpoint "/pets/{petId}" at provides rest, dynamic path segments must use *
Written as /pets/*, it publishes, and it matches a consumer that also writes /pets/*.
Requests#
request names the schema of the request body, as NewPet above. A body exists only on post, put and patch, so request is accepted on those three methods and nowhere else. A method may have a request and no responses.
Responses#
responses maps a status code to the schema of the response body, as 201: Pet above. A status code is an integer from 100 to 599, quoted or not; patterns such as 2xx are rejected.
Which statuses to declare#
Each status is its own resource, so the statuses each side lists decide what can break. A status the consumer declares must be declared by the provider, or it breaks with petstore_web reads response 404, but petstore_api answers only 200; a status only the provider declares obliges no consumer.
- A consumer declares a status when its code does something specific with it or reads its body. Handling that treats any error the same way does not count.
- A provider declares the statuses its code actually returns. A branch that never runs is left out.
petstore_web shows a "pet not found" page on a 404 without reading its body, so its 404 is ~ (Bodies not described), and it shows one generic message for every other error:
consumes: petstore_api: rest: /pets/*: get: responses: 200: Pet 404: ~
Bodies not described#
~ in place of a schema name, as in request: ~ or 200: ~, is a body the contract does not describe (The contract file says what that means for each side). A status left without a value, such as 204:, is the same ~, since YAML reads both as null. Write ~ for a response without a body, and for a request or response body that is a file or a multipart form:
provides: rest: /files: post: request: ~ responses: 201: File /files/*: get: responses: 200: ~ /pets/*: delete: responses: 204:
The resource still exists, so a consumer that calls DELETE /pets/* matches it. Against a counterpart, with the consumer under check (a provider under check that drops a request gets the removed break of Resource breaks):
| Provider | Consumer | Result |
|---|---|---|
request: ~ | request: NewFile | compatible |
no request | request: NewFile | break: petstore_web sends a request body, but petstore_api declares none |
200: ~ | 200: ~ | compatible |
200: Pet | 200: ~ | compatible |
200: ~ | 200: Pet | break: Pet β petstore_web reads it, but petstore_api doesn't provide it, at the body |
In several files#
A provider's files may split its endpoints, the methods of one endpoint and even the statuses of one method between them, as long as each resource is declared once (Several files). A request has no status, so the request of an endpoint and method belongs in exactly one file, even when its responses are spread over several. A provider that keeps the 201 of POST /pets in pets.yaml and its 400 in pets_errors.yaml writes request: NewPet in only one of them; writing it in both declares the request of POST /pets twice:
contract validation failed - pets_errors.yaml: duplicate resource "provides POST /pets request", also declared in pets.yaml
What is not compared#
The rest block has no key for the items below, so a change in any of them never makes can-i-deploy fail, and a key written for one, such as headers, is rejected at publish as an unknown key. The items that hold for every kind of resource are in The contract file.
- Headers. A provider that starts requiring one, and a consumer that stops sending one, both pass.
- Query parameters. A renamed parameter, a newly required one, or a change in how pagination is requested is not a break.