Skip to content

feat: give each documented status its own error class - #17

Draft
simonx1 wants to merge 1 commit into
obie:mainfrom
simonx1:feat/typed-http-error-classes
Draft

simonx1 wants to merge 1 commit into
obie:mainfrom
simonx1:feat/typed-http-error-classes

Conversation

@simonx1

@simonx1 simonx1 commented Sep 18, 2026

Copy link
Copy Markdown

401, 413, 422, 429 and 529 had classes. 400, 403, 404 and every other 5xx arrived as a bare ApiError, so telling a malformed request from a revoked key from a wrong base URL from an outage meant reading #status and writing the branch yourself — in a rescue, where a case on an integer is the worst place for it.

Adds BadRequest (400), PermissionDenied (403), NotFound (404) and ServerError (any 5xx), named after the classes the official Typesafe SDKs raise, so code written against those reads the same here.

Overloaded becomes a ServerError: rescue ServerError now covers every 5xx including 529, and rescue Overloaded still picks out the one the API documents by name. The status-to-class mapping is a table rather than a case, and an undocumented status still lands on ApiError.

Tests

test/error_classes_test.rb, 8 cases covering every mapped status plus the fallbacks.


Draft: part of a security and API-coverage audit, opened for reference rather than as a request for immediate review. Independent of the other branches, each off main. Suite green on Ruby 3.2.11, 3.3.8 and 3.4.8.

🤖 Generated with Claude Code

401, 413, 422, 429, and 529 had classes. 400, 403, 404, and every other
5xx arrived as a bare ApiError, so telling a malformed request from a
revoked key from a wrong base URL from an outage meant reading #status
and writing the branch yourself -- in a rescue, where a case on an
integer is the worst place for it.

Add BadRequest, PermissionDenied, NotFound, and ServerError, named after
the classes the official Typesafe SDKs raise, so code written against
those reads the same here. Overloaded becomes a ServerError: `rescue
ServerError` now covers every 5xx including 529, and `rescue Overloaded`
still picks out the one the API documents by name.

The status-to-class mapping is a table rather than a case, and an
undocumented status still lands on ApiError.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant