diff --git a/openapi/components/responses/BadRequest.yaml b/openapi/components/responses/BadRequest.yaml index 69820e0..8dcd599 100644 --- a/openapi/components/responses/BadRequest.yaml +++ b/openapi/components/responses/BadRequest.yaml @@ -3,3 +3,19 @@ content: application/problem+json: schema: $ref: ../schemas/Error.yaml + examples: + ValidationFailed: + summary: Request body failed validation + dataValue: + type: about:blank + title: Validation failed + status: 400 + instance: /orders + details: + errors: + - code: invalid_type + expected: string + received: undefined + path: + - customerName + message: Required diff --git a/openapi/components/responses/Conflict.yaml b/openapi/components/responses/Conflict.yaml index 5a4a8f9..b3e9f32 100644 --- a/openapi/components/responses/Conflict.yaml +++ b/openapi/components/responses/Conflict.yaml @@ -3,3 +3,11 @@ content: application/problem+json: schema: $ref: ../schemas/Error.yaml + examples: + DuplicateName: + summary: Menu item name is already taken + dataValue: + type: about:blank + title: A menu item with the name "coffee" already exists + status: 409 + instance: /menu diff --git a/openapi/components/responses/Forbidden.yaml b/openapi/components/responses/Forbidden.yaml index 6166b76..1d74551 100644 --- a/openapi/components/responses/Forbidden.yaml +++ b/openapi/components/responses/Forbidden.yaml @@ -3,3 +3,11 @@ content: application/problem+json: schema: $ref: ../schemas/Error.yaml + examples: + InsufficientScopes: + summary: Access token lacks the required scope + dataValue: + type: about:blank + title: 'Insufficient scopes. Required: orders:read' + status: 403 + instance: /orders diff --git a/openapi/components/responses/InternalServerError.yaml b/openapi/components/responses/InternalServerError.yaml index 07bd4ea..3677788 100644 --- a/openapi/components/responses/InternalServerError.yaml +++ b/openapi/components/responses/InternalServerError.yaml @@ -3,3 +3,11 @@ content: application/problem+json: schema: $ref: ../schemas/Error.yaml + examples: + InternalServerError: + summary: Unexpected server error + dataValue: + type: about:blank + title: Internal Server Error + status: 500 + instance: /orders diff --git a/openapi/components/responses/NotFound.yaml b/openapi/components/responses/NotFound.yaml index 5b507cb..ee9387a 100644 --- a/openapi/components/responses/NotFound.yaml +++ b/openapi/components/responses/NotFound.yaml @@ -3,3 +3,25 @@ content: application/problem+json: schema: $ref: ../schemas/Error.yaml + examples: + NotFound: + summary: No resource at this path + dataValue: + type: about:blank + title: Cannot GET /.well-known/oauth-authorization-server + status: 404 + instance: /.well-known/oauth-authorization-server + MenuItemNotFound: + summary: No menu item with this ID + dataValue: + type: about:blank + title: Menu item not found + status: 404 + instance: /menu/prd_01h1s5z6vf2mm1mz3hevnn9va7 + OrderNotFound: + summary: No order with this ID + dataValue: + type: about:blank + title: Order not found + status: 404 + instance: /orders/ord_01h1s5z6vf2mm1mz3hevnn9va7 diff --git a/openapi/components/responses/OAuth2BadRequest.yaml b/openapi/components/responses/OAuth2BadRequest.yaml index cae087a..2655ad9 100644 --- a/openapi/components/responses/OAuth2BadRequest.yaml +++ b/openapi/components/responses/OAuth2BadRequest.yaml @@ -5,3 +5,14 @@ content: application/json: schema: $ref: ../schemas/OAuthError.yaml + examples: + InvalidGrant: + summary: Refresh token is invalid or expired + dataValue: + error: invalid_grant + error_description: Invalid refresh token + InvalidClientMetadata: + summary: Requested scope does not exist + dataValue: + error: invalid_client_metadata + error_description: "scopes: Invalid enum value. Expected 'menu:read' | 'menu:write' | 'orders:read' | 'orders:write' | 'revenue:read', received 'admin'" diff --git a/openapi/components/responses/OAuth2ServerError.yaml b/openapi/components/responses/OAuth2ServerError.yaml index d4fd6cc..73c539b 100644 --- a/openapi/components/responses/OAuth2ServerError.yaml +++ b/openapi/components/responses/OAuth2ServerError.yaml @@ -3,3 +3,9 @@ content: application/json: schema: $ref: ../schemas/OAuthError.yaml + examples: + ServerError: + summary: Unexpected server error + dataValue: + error: server_error + error_description: An internal error occurred diff --git a/openapi/components/responses/OAuth2Unauthorized.yaml b/openapi/components/responses/OAuth2Unauthorized.yaml index 091f071..c6e9d02 100644 --- a/openapi/components/responses/OAuth2Unauthorized.yaml +++ b/openapi/components/responses/OAuth2Unauthorized.yaml @@ -10,3 +10,14 @@ content: application/json: schema: $ref: ../schemas/OAuthError.yaml + examples: + InvalidClient: + summary: Wrong client_id or client_secret + dataValue: + error: invalid_client + error_description: Invalid client credentials + InvalidToken: + summary: Wrong registration access token + dataValue: + error: invalid_token + error_description: Invalid registration access token diff --git a/openapi/components/responses/Unauthorized.yaml b/openapi/components/responses/Unauthorized.yaml index 74c6f8c..8a7471e 100644 --- a/openapi/components/responses/Unauthorized.yaml +++ b/openapi/components/responses/Unauthorized.yaml @@ -3,3 +3,11 @@ content: application/problem+json: schema: $ref: ../schemas/Error.yaml + examples: + BearerTokenRequired: + summary: Missing access token + dataValue: + type: about:blank + title: Bearer token is required + status: 401 + instance: /orders diff --git a/openapi/paths/revenue.yaml b/openapi/paths/revenue.yaml index b5bc42e..ad38010 100644 --- a/openapi/paths/revenue.yaml +++ b/openapi/paths/revenue.yaml @@ -22,7 +22,7 @@ get: format: date-time examples: StartOfJanuary: - summary: Start of January 2026 + summary: January 1, 2026 dataValue: '2026-01-01T00:00:00Z' - name: endDate in: query @@ -35,7 +35,7 @@ get: format: date-time examples: EndOfJanuary: - summary: End of January 2026 + summary: January 31, 2026 dataValue: '2026-01-31T23:59:59Z' responses: '200': diff --git a/redocly.yaml b/redocly.yaml index c7373f6..6247e06 100644 --- a/redocly.yaml +++ b/redocly.yaml @@ -3,18 +3,36 @@ extends: apis: cafe-api: root: "./openapi/cafe.yaml" - rules: - rule/operation-summary: - subject: - type: Operation - property: summary - where: - - subject: - type: Paths - assertions: - defined: true + +rules: + operation-tag-defined: error + no-invalid-schema-examples: error + no-invalid-media-type-examples: error + rule/operation-summary: + subject: + type: Operation + property: summary + where: + - subject: + type: Paths assertions: - pattern: /^(Create|Get|Retrieve|Replace|Update|Delete|Login|Send|Callback|Cancel|List|Partially update|Revoke).*[^\.]$/ + defined: true + assertions: + pattern: /^(Create|Get|Retrieve|Replace|Update|Delete|Login|Send|Callback|Cancel|List|Partially update|Revoke).*[^\.]$/ + rule/operation-summary-sentence-case: + subject: + type: Operation + property: summary + message: Operation summary must be sentence cased. + assertions: + pattern: /^([A-Z]{2,}|[A-Z][^A-Z]*|OAuth2)(?=\s|$)(\s+\(?(?:[A-Z]{2,}|[^A-Z]*|OAuth2)\)?(?=\s|$))*$/ + rule/example-summary-sentence-case: + subject: + type: Example + property: summary + message: Example summary must be sentence cased. + assertions: + pattern: /^([A-Z]{2,}|[A-Z][^A-Z]*|OAuth2)(?=\s|$)(\s+\(?(?:[A-Z]{2,}|[^A-Z]*|OAuth2)\)?(?=\s|$))*$/ logo: srcSet: "./images/cafe-logo-black.svg light, ./images/cafe-logo-white.svg dark"