Errors
The SDK raises a fixed hierarchy under PoliPage::Error. This gem adds one class, PoliPage::Rails::ConfigurationError, and a default handler that answers every PoliPage::Error an action raises, so an unrescued error becomes a JSON response instead of a 500 page.
The error
Section titled “The error”PoliPage::Error carries code, status, request_id and message. These are the categories you usually branch on:
- Auth:
PoliPage::AuthenticationError,PoliPage::PermissionDeniedError. A bad or revoked key, or a blocked organization. - Rate limit:
PoliPage::RateLimitError. The API answered429. - Request rejected:
PoliPage::ValidationError. The template, project ordatawas rejected with400. - Network and transport:
PoliPage::ConnectionError,PoliPage::TimeoutError.
PoliPage::InvalidResponseError (invalid_response) is raised when a 2xx answer’s body is not JSON, usually because of a proxy. PoliPage::FileWriteError (io_error) is raised when render_to_file cannot write its file.
PoliPage::Rails::ConfigurationError inherits from PoliPage::Error and has the code configuration_error and no status. It is raised on the first PoliPage.client call when the initializer is invalid, so one rescue PoliPage::Error catches everything.
What the handler answers
Section titled “What the handler answers”The Railtie includes PoliPage::Rails::ErrorHandler into ActionController::Base and ActionController::API. It does a rescue_from PoliPage::Error and renders the SDK’s Error#to_payload as JSON, as is:
{ "code": "TEMPLATE_NOT_FOUND", "message": "Template 'does-not-exist' not found in project 'getting-started'.", "status": 404, "requestId": "req_…" }| Error | HTTP status | Body status |
| --- | --- | --- |
| An API error | the API’s status | the API’s status |
| network_error | 503 | 503 |
| timeout | 504 | 504 |
| invalid_response | 502 | 502 |
| No status, for example configuration_error or io_error | 500 | null |
requestIdis the API’sx-request-id, ornullwhen there is none.- The
Content-Typeisapplication/json, even when the action had already set another one, as a PDF route does. - The keys are the SDK’s, spelled the same by every Poli Page SDK. Your app’s inflections, an
IDacronym for example, do not change them.
Live streams
Section titled “Live streams”The handler cannot answer once the response is committed, and an ActionController::Live stream is committed when it writes its first chunk or is closed. It then raises the error again, so Live logs it and calls the stream’s on_error. The client gets a short 200, the PDF cut where the error happened. To detect this, compare the bytes received with the descriptor’s sizeBytes.
For an error before the first byte to get the JSON answer, in a Live action:
- set the PDF headers and write the first chunk only after the SDK call has started;
- close the stream only once you have written to it (
ensure response.stream.close if started). The usual unconditionalensure response.stream.closecommits an empty200before the handler runs.
Handle errors yourself
Section titled “Handle errors yourself”A rescue_from in your own controllers, for PoliPage::Error, one of its subclasses or StandardError, takes precedence over the handler, as usual in Rails. To leave the handler out entirely:
Rails.application.config.poli_page.tap do |c| c.error_handler = falseendThe value must be true or false: the app refuses to boot with anything else.
Example
Section titled “Example”class InvoicesController < ApplicationController include PoliPage::Rails::Renderable
def show bytes = PoliPage.client.render.pdf( project: "billing", template: "invoice", data: { invoiceNumber: "INV-001" } ) render_pdf(bytes, filename: "invoice.pdf") rescue PoliPage::ValidationError => e Rails.logger.warn("PoliPage validation failed: #{e.message}") head :unprocessable_entity rescue PoliPage::RateLimitError head :too_many_requests rescue PoliPage::AuthenticationError, PoliPage::PermissionDeniedError head :forbidden rescue PoliPage::ConnectionError, PoliPage::TimeoutError head :bad_gateway endend