From 3522f998e8bfb87f10f015b3b6f2904bec99ff7b Mon Sep 17 00:00:00 2001 From: Joren De Groof Date: Wed, 8 Jul 2026 09:34:33 +0200 Subject: [PATCH 1/2] Expose response via the error In case you want to use the headers of the response when hitting the rate limit. This way you don't need to regex your way through the message. --- lib/frontapp/error.rb | 2 ++ spec/error_spec.rb | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/frontapp/error.rb b/lib/frontapp/error.rb index db7f2f1..968fce9 100644 --- a/lib/frontapp/error.rb +++ b/lib/frontapp/error.rb @@ -1,5 +1,7 @@ module Frontapp class Error < StandardError + attr_reader :response + def self.from_response(response) error_class = case response.status when 400 then BadRequestError diff --git a/spec/error_spec.rb b/spec/error_spec.rb index 555e96e..6d7c51e 100644 --- a/spec/error_spec.rb +++ b/spec/error_spec.rb @@ -49,4 +49,24 @@ frontapp.get_contact(1) end.to raise_error(Frontapp::TooManyRequestsError) end + + it "exposes response headers on the error" do + stub_request(:get, "#{base_url}/contacts/1"). + with(headers: headers). + to_return( + status: 429, + body: '{"_error":{"message":"Rate limited"}}', + headers: { + "Retry-After" => "17", + "x-ratelimit-remaining" => "0", + } + ) + + frontapp.get_contact(1) + rescue Frontapp::TooManyRequestsError => e + expect(e.response).not_to be_nil + expect(e.response.status).to eq(429) + expect(e.response.headers["Retry-After"]).to eq("17") + expect(e.response.headers["x-ratelimit-remaining"]).to eq("0") + end end From d04b823d6b390c0298c73543ed405b93510515a4 Mon Sep 17 00:00:00 2001 From: Joren De Groof Date: Wed, 8 Jul 2026 09:37:31 +0200 Subject: [PATCH 2/2] Update README with error handling and rate limits --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index fd6a4ff..131ed51 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,20 @@ Optionally, set a custom user agent to identify your integration client = Frontapp::Client.new(auth_token: 'token', user_agent: 'Eye-Phone Integration (engineering@planet-express.com') ``` +### Errors & Rate Limits + +When the API returns an error, a specific exception is raised (`Frontapp::BadRequestError`, `Frontapp::UnauthorizedError`, `Frontapp::NotFoundError`, `Frontapp::ConflictError`, `Frontapp::TooManyRequestsError`). The response object is accessible on the error for inspecting headers and status: + +```ruby +begin + client.get_contact("ctc_55c8c149") +rescue Frontapp::TooManyRequestsError => e + retry_after = e.response.headers["Retry-After"] + sleep(retry_after.to_i) + retry +end +``` + ### Attachments ```ruby # Download a file attachment @@ -437,3 +451,4 @@ Special thanks to: - [feolea](https://github.com/feolea) - [jefferal1995](https://github.com/jefferal1995) - [panozzaj](https://github.com/panozzaj) +- [joren](https://github.com/joren)