Skip to content

MT-21122: updated responces#35

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

MT-21122: updated responces#35
GannaRW wants to merge 4 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 resources now return a nested tree; organization added as a resource type.
    • Sandbox inbox messages include template_id, template_variables, enhanced blacklist and SMTP details.
    • Contacts fields expanded (Birthdate, Cats count) and field schema standardized.
  • Documentation

    • Many endpoints updated with clearer server descriptions and concrete error examples across APIs.
  • Refactor

    • Error/response schemas reorganized for consistent shapes and per-attribute validation examples (UnprocessableEntity).

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aeaf70d2-e8a5-4bc0-92b6-fa5e1cd20118

📥 Commits

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

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

📝 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.
Account-management endpoints
specs/account-management.openapi.yml
/permissions/resources now returns PermissionResourceNode $ref; organization sub-accounts 403 responses changed to PermissionsDeniedResponse with examples; AccountAccess.resources enum and wrapper 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.

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

  • mailtrap/mailtrap-openapi#4: Both PRs touch the Organizations sub-accounts API surface — adding/altering the /api/organizations/{organization_id}/sub_accounts endpoints and related sub-account schemas/error responses.
  • mailtrap/mailtrap-openapi#17: Prior multi-file spec reorganizations that this PR builds on across account-management, templates, and sandbox files.
  • mailtrap/mailtrap-openapi#29: Touched the same account-management permissions/resources endpoint and may overlap with the PermissionResourceNode change.

Suggested Reviewers

  • IgorDobryn
  • leonid-shevtsov
  • 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 The title 'MT-21122: updated responces' is vague and contains a typo; it doesn't clearly convey that this PR aligns OpenAPI error response bodies and schemas across multiple specs with production APIs. Revise the title to be more descriptive, such as 'MT-21122: Align OpenAPI error responses and schemas with production APIs' and fix the typo 'responces' to 'responses'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The PR description provides comprehensive details about changes across all affected OpenAPI specs, aligning with the repository's template structure with Motivation and Changes sections, though the 'How to test' section lacks specific test steps.
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.

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.

2 participants