Skip to content

MT-21122: updated responces#35

Open
GannaRW wants to merge 5 commits intomainfrom
MT-21122_update_responses
Open

MT-21122: updated responces#35
GannaRW wants to merge 5 commits intomainfrom
MT-21122_update_responses

Conversation

@GannaRW
Copy link
Copy Markdown

@GannaRW GannaRW commented May 4, 2026

https://railsware.atlassian.net/browse/MT-21122
Align OpenAPI error bodies and message/schemas with production APIs

Changes

specs/sandbox.openapi.yml

  • 401 / 403 / 404: Shared responses now include explicit JSON examples (Incorrect API token, Account access forbidden, Not Found).
  • Sandbox messages: Introduced SandboxInboxMessage: blacklists_report_info as an object (not a boolean), plus template_id, template_variables, and smtp_information.data.rcpt_to_addrs. GET message list uses this schema; GET single message no longer uses a misleading oneOf.

specs/account-management.openapi.yml

  • 401 / 403 / 404: Examples aligned with other account specs.
    AccountAccess: Added organization to resources[].resource_type (observed in production).
    GET .../permissions/resources: Recursive PermissionResourceNode replaces a shallow nested schema; example reflects real hierarchy.
  • PermissionsDeniedResponse: Documents that errors text can vary.
    GET / POST /api/organizations/.../sub_accounts: 403 example documents Access forbidden (org vs account messaging).

specs/contacts.openapi.yml

  • 401 / 403 / 404 / 429 / 500: Examples and schema-level examples added where useful; PermissionsDeniedResponse notes message variance.
  • Contact fields: GET list examples use data_type (not type).
  • DELETE contact 404: Documented as {"errors":"Contact(s) not found"} via ErrorResponse, separate from NOT_FOUND’s error field.

specs/templates.openapi.yml

  • 401 / 403 / 404: Switched from success + errors array to account-style UnauthenticatedResponse, PermissionsDeniedResponse, NotFoundResponse with examples.
  • Examples / parameters: Quoted template uuid; improved parameter examples.

specs/email-sending-bulk.openapi.yml & specs/email-sending-transactional.openapi.yml

  • Confirmed bulk.api / send.api errors: {"success":false,"errors":["…"]}.
  • Servers: Note to use a normal User-Agent (edge / Cloudflare behavior).
  • SendEmailErrorResponse: Description + schema example.
  • BadRequest: Multi-string errors example (empty send body).
  • Forbidden / InternalError: Response examples added.

specs/email-sending.openapi.yml (mailtrap.io account API)

  • Servers: Clarifies account API vs sending hosts and error families.
  • 401 / 403 / 404: Replaced ErrorResponse with UnauthenticatedResponse, PermissionsDeniedResponse, NotFoundResponse + examples.
  • BadRequest: Optional error; documents possible empty 400 body.
  • RateLimitExceededResponse: errors as a string; LIMIT_EXCEEDED example updated.
  • UnprocessableEntity: Schema + response example from a real 422.

specs/sandbox-sending.openapi.yml

  • Servers: Sending-style errors vs account API; User-Agent note.
  • SendEmailErrorResponse: Description + example.
  • POST /api/send/{inbox_id}: example on 400, 401, 429, 500.
  • POST /api/batch/{inbox_id}: example on 400, 401, 500.

How to test

  • apply updated files
  • check documentation reflects real API responses

Summary by CodeRabbit

  • New Features

    • Permissions now return a hierarchical resources tree; "organization" added as a resource type.
    • Sandbox inbox messages include template info, richer blacklist and SMTP details.
    • Contact field examples expanded (Birthdate, Cats count) and field format standardized.
  • Documentation

    • Server descriptions clarified and many endpoints now include concrete, consistent error examples.
  • Refactor

    • Error/response shapes reorganized with explicit examples and per-attribute validation details (UnprocessableEntity).

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR updates multiple OpenAPI spec files to standardize error response schemas and examples, add/replace several schemas (permission/resource and sandbox message models), refine parameter formats and server descriptions, and replace inline responses with explicit schema references across account-management, contacts, email-sending, sandbox, and templates specs.

Changes

OpenAPI specs — error-schema consolidation, examples, and domain model updates

Layer / File(s) Summary
Data Shape
specs/account-management.openapi.yml, specs/sandbox.openapi.yml, specs/templates.openapi.yml
Added PermissionResourceNode (recursive) and SandboxInboxMessage; AccountAccess.resources enum now includes organization; path params account_id/email_template_id set to format: int64; message schema fields template_id, template_variables, and blacklists_report_info reshaped; UnprocessableEntity supports per-attribute errors.
Sending servers & error format
specs/email-sending*.openapi.yml, specs/sandbox-sending.openapi.yml
Expanded servers[].description guidance and standardized sending-endpoint errors to { success: false, errors: [...] }; updated SendEmailErrorResponse descriptions and examples; BadRequest/Unauthorized/Forbidden/Internal examples updated for bulk/transactional/sandbox sending specs.
Sandbox message wiring
specs/sandbox.openapi.yml
Replaced inline/oneOf message response models with $ref: SandboxInboxMessage for GET/list; updated SMTP and blacklists-report structures and related examples.
Contacts updates
specs/contacts.openapi.yml
DELETE contact 404 now documents inline ErrorResponse example; ContactField entries updated to use data_type and added Birthdate and Cats count; UnprocessableEntity supports per-attribute error arrays and inline duplicate-409 examples were removed.
Account-management endpoints
specs/account-management.openapi.yml
/permissions/resources now returns PermissionResourceNode $ref; organization sub-accounts 403 responses changed to explicit PermissionsDeniedResponse with examples; shared wrapper examples and UnprocessableEntity typing/examples updated.
Response wrappers & examples
specs/email-sending.openapi.yml, specs/contacts.openapi.yml, specs/account-management.openapi.yml, specs/templates.openapi.yml
Introduced/updated dedicated error schemas: BadRequest, UnauthenticatedResponse, PermissionsDeniedResponse, NotFoundResponse, RateLimitExceededResponse; replaced generic ErrorResponse usages; added concrete application/json examples for UNAUTHENTICATED, PERMISSION_DENIED, NOT_FOUND, BAD_REQUEST, LIMIT_EXCEEDED, INTERNAL_ERROR.
Examples & Minor adjustments
specs/templates.openapi.yml, specs/contacts.openapi.yml, specs/email-sending-bulk.openapi.yml
Updated EmailTemplateResponse.example.uuid to a quoted UUID string; contact field examples adjusted; bulk/transactional sending examples list multiple validation messages; server descriptions clarified for sending/sandbox contexts.

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

Suggested Reviewers

  • IgorDobryn
  • leonid-shevtsov
  • yanchuk
  • VladimirTaytor

Poem

🐇 I hopped through YAML, tidy and spry,
I nested permissions and made examples clear,
Servers now whisper the UA rules to send,
Errors aligned so clients know what to fear,
A little hop, a doc fix—cheer! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive Title contains a typo ("responces" instead of "responses") and lacks specificity about the main changes across multiple OpenAPI specs. Correct the typo and make the title more specific, e.g., 'MT-21122: align OpenAPI error response examples with production APIs' or 'MT-21122: standardize error schemas and examples across OpenAPI specs'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed Description is comprehensive and well-structured with clear per-file change summaries, objective explanation of the motivation, and testing instructions aligned with the template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch MT-21122_update_responses

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
specs/account-management.openapi.yml (1)

1047-1053: ⚡ Quick win

Duplicate inline 403 responses — consider extracting a shared response component.

The 403 block under GET /api/organizations/{organization_id}/sub_accounts (lines 1047–1053) and POST /api/organizations/{organization_id}/sub_accounts (lines 1109–1115) are byte-for-byte identical. Since they intentionally differ from the shared PERMISSION_DENIED component (different description and example value), they can't reuse that component as-is — but they can share a new one:

♻️ Suggested refactor

Add to components/responses:

+    ORG_PERMISSION_DENIED:
+      description: Insufficient organization permissions or wrong organization.
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/PermissionsDeniedResponse'
+          example:
+            errors: Access forbidden

Then replace both inline 403 blocks:

-        '403':
-          description: Insufficient organization permissions or wrong organization.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/PermissionsDeniedResponse'
-              example:
-                errors: Access forbidden
+        '403':
+          $ref: '#/components/responses/ORG_PERMISSION_DENIED'

(apply to both the GET and POST operations)

Also applies to: 1109-1115

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@specs/account-management.openapi.yml` around lines 1047 - 1053, Two
operations (GET /api/organizations/{organization_id}/sub_accounts and POST
/api/organizations/{organization_id}/sub_accounts) contain identical inline 403
responses that differ from the existing PERMISSION_DENIED component; extract
them into a single new response component (e.g.,
ORGANIZATION_PERMISSIONS_DENIED) under components/responses preserving the
description and example, then replace the inline 403 blocks in both operations
with a $ref to that new component and remove the duplicated inline definitions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@specs/account-management.openapi.yml`:
- Around line 1047-1053: Two operations (GET
/api/organizations/{organization_id}/sub_accounts and POST
/api/organizations/{organization_id}/sub_accounts) contain identical inline 403
responses that differ from the existing PERMISSION_DENIED component; extract
them into a single new response component (e.g.,
ORGANIZATION_PERMISSIONS_DENIED) under components/responses preserving the
description and example, then replace the inline 403 blocks in both operations
with a $ref to that new component and remove the duplicated inline definitions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 638f6324-2549-4286-8c26-52005091f87e

📥 Commits

Reviewing files that changed from the base of the PR and between 23d52c3 and 55d6c75.

📒 Files selected for processing (8)
  • specs/account-management.openapi.yml
  • specs/contacts.openapi.yml
  • specs/email-sending-bulk.openapi.yml
  • specs/email-sending-transactional.openapi.yml
  • specs/email-sending.openapi.yml
  • specs/sandbox-sending.openapi.yml
  • specs/sandbox.openapi.yml
  • specs/templates.openapi.yml

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
specs/email-sending.openapi.yml (1)

2970-2977: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Split empty-body and JSON 400s into separate response components.

The BadRequest schema explicitly states: "Some endpoints return an empty body with HTTP 400; when present, a message may use an error field." However, the shared BAD_REQUEST response still unconditionally declares application/json content. This forces all 7 operations that reference it to be documented as always returning a JSON body, contradicting the schema's documented behavior. Either remove content from BAD_REQUEST or introduce a BAD_REQUEST_JSON component for endpoints with guaranteed JSON payloads, ensuring the spec accurately reflects actual behavior and compliance with OpenAPI 3.1.

Possible direction
   responses:
     BAD_REQUEST:
-      description: Bad request - invalid parameters.
-      content:
-        application/json:
-          schema:
-            $ref: '#/components/schemas/BadRequest'
-          example:
-            error: Bad Request
+      description: Bad request - invalid parameters. Some endpoints may return an empty body.
+
+    BAD_REQUEST_JSON:
+      description: Bad request - invalid parameters.
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/BadRequest'
+          example:
+            error: Bad Request
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@specs/email-sending.openapi.yml` around lines 2970 - 2977, The shared
BAD_REQUEST response currently declares application/json content but the
referenced components/schemas/BadRequest allows empty 400 bodies; update the
OpenAPI responses so they reflect both variants: create a new response component
BAD_REQUEST_JSON that includes the application/json content and schema
(referencing components/schemas/BadRequest), and change the existing BAD_REQUEST
component to have no content (only description) for endpoints that may return an
empty body; then update the seven operations that reference BAD_REQUEST to point
to BAD_REQUEST_JSON only where JSON is guaranteed and leave the rest using the
empty-body BAD_REQUEST component.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@specs/contacts.openapi.yml`:
- Around line 2790-2804: The UnprocessableEntity schema defines errors.<field>
as string[] but several 422 response examples violate this; update the examples
for the endpoints PATCH /contacts/{contact_identifier}
(errors.list_id_included/0), POST /contacts/fields (errors.merge_tag/0 and
errors.name/0), and POST /contacts/exports (errors.filters) so each error value
is an array of strings (e.g., ["contains invalid data"] or ["invalid"]) to match
the UnprocessableEntity schema, or alternatively update the UnprocessableEntity
schema to accept nested arrays/scalars if you intentionally want those
shapes—ensure the chosen fix is applied consistently and the specs remain
OpenAPI 3.1 compliant.

---

Outside diff comments:
In `@specs/email-sending.openapi.yml`:
- Around line 2970-2977: The shared BAD_REQUEST response currently declares
application/json content but the referenced components/schemas/BadRequest allows
empty 400 bodies; update the OpenAPI responses so they reflect both variants:
create a new response component BAD_REQUEST_JSON that includes the
application/json content and schema (referencing components/schemas/BadRequest),
and change the existing BAD_REQUEST component to have no content (only
description) for endpoints that may return an empty body; then update the seven
operations that reference BAD_REQUEST to point to BAD_REQUEST_JSON only where
JSON is guaranteed and leave the rest using the empty-body BAD_REQUEST
component.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fad0e953-86a1-42fd-a1b3-6d8f74aa69ef

📥 Commits

Reviewing files that changed from the base of the PR and between 55d6c75 and 86b3906.

📒 Files selected for processing (3)
  • specs/account-management.openapi.yml
  • specs/contacts.openapi.yml
  • specs/email-sending.openapi.yml

Comment on lines 2790 to 2804
title: UnprocessableEntity
type: object
properties:
errors:
type: object
description: Validation errors per attribute. Entire record errors are under `base` key.
additionalProperties:
type: array
items:
type: string
example:
errors:
email:
- can't be blank
examples: {}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python -m pip install --quiet pyyaml jsonschema >/dev/null
python - <<'PY'
import yaml
from jsonschema import Draft202012Validator
from pathlib import Path

spec = yaml.safe_load(Path("specs/contacts.openapi.yml").read_text())
schema = spec["components"]["schemas"]["UnprocessableEntity"]
validator = Draft202012Validator(schema)

targets = [
    (
        "PATCH /api/accounts/{account_id}/contacts/{contact_identifier} 422",
        spec["paths"]["/api/accounts/{account_id}/contacts/{contact_identifier}"]["patch"]["responses"]["422"]["content"]["application/json"]["example"],
    ),
    (
        "POST /api/accounts/{account_id}/contacts/{contact_identifier}/events 422",
        spec["paths"]["/api/accounts/{account_id}/contacts/{contact_identifier}/events"]["post"]["responses"]["422"]["content"]["application/json"]["example"],
    ),
    (
        "POST /api/accounts/{account_id}/contacts/exports 422",
        spec["paths"]["/api/accounts/{account_id}/contacts/exports"]["post"]["responses"]["422"]["content"]["application/json"]["example"],
    ),
    (
        "POST /api/accounts/{account_id}/contacts/fields 422",
        spec["paths"]["/api/accounts/{account_id}/contacts/fields"]["post"]["responses"]["422"]["content"]["application/json"]["example"],
    ),
    (
        "PATCH /api/accounts/{account_id}/contacts/fields/{field_id} 422",
        spec["paths"]["/api/accounts/{account_id}/contacts/fields/{field_id}"]["patch"]["responses"]["422"]["content"]["application/json"]["example"],
    ),
]

for name, example in targets:
    errors = list(validator.iter_errors(example))
    if not errors:
        print(f"{name}: OK")
        continue

    print(f"{name}: INVALID")
    for err in errors[:3]:
        path = "/".join(str(p) for p in err.path) or "<root>"
        print(f"  - {path}: {err.message}")
PY

Repository: mailtrap/mailtrap-openapi

Length of output: 1393


Fix incompatibility between UnprocessableEntity schema and 422 response examples

The UnprocessableEntity schema restricts errors.<field> to string[], but multiple 422 response examples in this file violate this constraint. For example:

  • PATCH /contacts/{contact_identifier}: errors.list_id_included/0 shown as nested array ['contains invalid data'] instead of string
  • POST /contacts/fields: errors.merge_tag/0 and errors.name/0 shown as nested arrays
  • POST /contacts/exports: errors.filters shown as scalar string 'invalid' instead of array

Normalize all 422 examples to conform to the schema, or adjust the schema to accept the current structures. Per coding guidelines, specifications must be compliant with OpenAPI 3.1 standard.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@specs/contacts.openapi.yml` around lines 2790 - 2804, The UnprocessableEntity
schema defines errors.<field> as string[] but several 422 response examples
violate this; update the examples for the endpoints PATCH
/contacts/{contact_identifier} (errors.list_id_included/0), POST
/contacts/fields (errors.merge_tag/0 and errors.name/0), and POST
/contacts/exports (errors.filters) so each error value is an array of strings
(e.g., ["contains invalid data"] or ["invalid"]) to match the
UnprocessableEntity schema, or alternatively update the UnprocessableEntity
schema to accept nested arrays/scalars if you intentionally want those
shapes—ensure the chosen fix is applied consistently and the specs remain
OpenAPI 3.1 compliant.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
specs/templates.openapi.yml (1)

586-616: 💤 Low value

Redundant property-level example alongside schema-level example

Each new schema (UnauthenticatedResponse, PermissionsDeniedResponse, NotFoundResponse) defines example both at the individual property level and at the schema object level. The schema-level example already covers everything a renderer needs; the property-level examples are redundant.

♻️ Proposed cleanup (one schema shown; same applies to the other two)
     UnauthenticatedResponse:
       title: UnauthenticatedResponse
       type: object
       properties:
         error:
           type: string
           description: Error message
-          example: Incorrect API token
       example:
         error: Incorrect API token
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@specs/templates.openapi.yml` around lines 586 - 616, Remove the redundant
property-level "example" entries and keep only the schema-level "example" for
each response schema: update UnauthenticatedResponse by deleting the example
under the "error" property and keep the top-level example, update
PermissionsDeniedResponse by deleting the example under the "errors" property
and keep the top-level example, and update NotFoundResponse by deleting the
example under the "error" property and keep the top-level example; ensure you
only remove the per-property "example" keys (not the properties themselves) in
UnauthenticatedResponse, PermissionsDeniedResponse, and NotFoundResponse.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@specs/templates.openapi.yml`:
- Around line 586-616: Remove the redundant property-level "example" entries and
keep only the schema-level "example" for each response schema: update
UnauthenticatedResponse by deleting the example under the "error" property and
keep the top-level example, update PermissionsDeniedResponse by deleting the
example under the "errors" property and keep the top-level example, and update
NotFoundResponse by deleting the example under the "error" property and keep the
top-level example; ensure you only remove the per-property "example" keys (not
the properties themselves) in UnauthenticatedResponse,
PermissionsDeniedResponse, and NotFoundResponse.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 62514599-df67-4752-ac84-5f4ba3e7019d

📥 Commits

Reviewing files that changed from the base of the PR and between bedc607 and 8f90835.

📒 Files selected for processing (3)
  • specs/account-management.openapi.yml
  • specs/contacts.openapi.yml
  • specs/templates.openapi.yml
🚧 Files skipped from review as they are similar to previous changes (2)
  • specs/account-management.openapi.yml
  • specs/contacts.openapi.yml

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants