Best Practices
Best practices
- Fail early at input boundaries. Validate incoming data immediately after decoding it. Throw explicit
<error>messages for missing or invalid fields before processing begins. - Always include a
<catch>block in any<try>that wraps code interacting with external systems (databases, APIs, file I/O). Unhandled errors from these sources produce raw technical messages that should never reach the client. - Use
<finally>for response formatting. Place your<header>and<output>statements in the<finally>block to ensure the response is always sent, even when errors occur. - Include enough error detail for troubleshooting but avoid leaking sensitive internals. The
detailsfield should help a developer reproduce the issue, not expose database schemas or internal paths. - Keep success and failure code paths equally explicit. Use the
<else>block for success-only logic rather than assuming "no error means success" at the end of the<try>body. - Return consistent error shapes. Every service should use the same JSON envelope structure for errors. Inconsistent error formats create client-side complexity.
- Wrap system boundaries in try/catch. JSON parsing, HTTP requests, database operations, and any external service calls should always be protected.
Common mistakes
- Letting parser/runtime errors bubble to the client unchanged. Without
<try>/<catch>, a<decode:json>failure produces a raw "Syntax error" message as the entire response — no JSON wrapper, no HTTP status code, no content type header. - Returning different error shapes per endpoint. This forces every client to handle errors differently for each API call.
- Swallowing exceptions without recording context. An empty
<catch>block hides failures, making debugging extremely difficult. - Placing output statements after the
<try>block instead of in<finally>. If an error occurs and the<catch>block doesn't produce output, the client receives an empty response. - Setting HTTP status and response payload inconsistently. For example, returning a
200status with an error payload, or a500status with a success payload. - Using
<error>for control flow instead of<if>/<return>. While<error>works for early exits, it incurs the overhead of exception handling. For expected conditions (like "record not found"), use<if>with<return>instead.