Errors
The SDK returns one error type, *polipage.Error, with predicate methods instead of a type per category. The middleware turns a queued *polipage.Error into a JSON answer, or you handle errors inline.
The error
Section titled “The error”Discriminate on these predicates, or on the sentinels with errors.Is:
- Auth:
err.IsAuthError()(HTTP 401 or 403, sentinelspolipage.ErrUnauthorizedandpolipage.ErrForbidden). - Rate limit:
err.IsRateLimitError()(HTTP 429, sentinelpolipage.ErrRateLimit). - Validation:
err.IsValidationError()(HTTP 400, sentinelpolipage.ErrValidation). The template or data was rejected. - Network:
err.IsNetworkError()(connection, DNS, TLS or timeout).
Every error carries Code, Message, StatusCode (zero for SDK-internal errors) and RequestID. Use errors.As to reach them.
What the error handler answers
Section titled “What the error handler answers”polipagegin.Middleware(client) installs the error handler by default. When a handler queues a *polipage.Error with c.Error(err) and writes no response, the middleware answers with Content-Type: application/json and the SDK’s err.ToPayload() as the body, unchanged:
{ "code": "TEMPLATE_NOT_FOUND", "message": "Template 'does-not-exist' not found in project 'getting-started'.", "status": 404, "requestId": "req_…" }| Case | HTTP status | Body status |
| --- | --- | --- |
| An API error | the API’s status | the API’s status |
| network_error | 503 | 503 |
| timeout | 504 | 504 |
| invalid_response (a 2xx whose body is not JSON, usually from a proxy) | 502 | 502 |
| An SDK error with no status, such as aborted or io_error | 500 | null |
requestId is null when the API sent none. code and message are the SDK’s, verbatim.
The handler is narrow on purpose:
- Only
*polipage.Erroris handled, and only the last error onc.Errors. Any other error is left for your own error handling. - A response the handler already wrote is never overwritten.
- Headers set for another answer (
Content-Disposition,X-Accel-Buffering,Content-Length, a PDFContent-Type) are dropped from the JSON answer.
polipagegin.WriteError(c, err) writes the same answer from inside a handler, for code paths that prefer explicit error rendering. A non-*polipage.Error argument gets a 500 with no body.
Handle errors yourself
Section titled “Handle errors yourself”Turn the handler off with one option, and use polipagegin.ErrorMiddleware() elsewhere in the chain if you want it on a single group:
r.Use(polipagegin.Middleware(client, polipagegin.WithoutErrorHandler()))Or branch inline:
pdf, err := client.Render.PDF(c.Request.Context(), input)if err != nil { var pe *polipage.Error if errors.As(err, &pe) { switch { case pe.IsAuthError(): c.AbortWithStatus(http.StatusUnauthorized) case pe.IsRateLimitError(): c.AbortWithStatus(http.StatusTooManyRequests) case pe.IsNetworkError(): c.AbortWithStatus(http.StatusBadGateway) default: c.AbortWithStatus(http.StatusInternalServerError) } return } c.AbortWithStatus(http.StatusInternalServerError) return}Example
Section titled “Example”func invoiceHandler(c *gin.Context) { client := polipagegin.ClientFrom(c)
pdf, err := client.Render.PDF(c.Request.Context(), polipage.RenderInput{ Project: "billing", Template: "invoice", Data: map[string]any{"invoiceNumber": "INV-001"}, }) if err != nil { _ = c.Error(err) // the middleware answers it as JSON return } polipagegin.PDF(c, pdf, polipagegin.PDFOptions{Filename: "invoice.pdf"})}