DEV Community

ThaSha
ThaSha

Posted on

RFC 7807 Error Responses in DataWeave: One Transform for All 14 Endpoints

Our API had 14 endpoints and 14 different error response formats. The mobile team spent 3 days writing separate error parsers for each one. I standardized everything to RFC 7807 with one DataWeave transform.

TL;DR

  • RFC 7807 defines a standard error format: type, title, status, detail, timestamp
  • One DataWeave error mapping lookup replaces 14 inconsistent formats
  • The default clause on the lookup is critical — unmapped errors return null without it
  • application/problem+json MIME type supported since Mule 4.4

The Problem: 14 Endpoints, 14 Error Formats

// Endpoint A
{"error": "not found"}

// Endpoint B
{"message": "Resource missing", "code": 404}

// Endpoint C
{"errors": [{"field": "email", "issue": "invalid"}]}
Enter fullscreen mode Exit fullscreen mode

The mobile team needed a different error parser for each endpoint. 3 days of defensive parsing just to show error messages.

The Solution: RFC 7807 Error Envelope

%dw 2.0
output application/json
var errorMapping = {
    "HTTP:BAD_REQUEST": { status: 400, title: "Bad Request", "type": "client-error" },
    "HTTP:UNAUTHORIZED": { status: 401, title: "Unauthorized", "type": "authentication" },
    "HTTP:NOT_FOUND": { status: 404, title: "Not Found", "type": "not-found" },
    "HTTP:TIMEOUT": { status: 504, title: "Gateway Timeout", "type": "timeout" }
}
var errorInfo = errorMapping[payload.error.errorType.identifier] default { status: 500, title: "Internal Server Error", "type": "server-error" }
---
{
  "type": "https://api.example.com/errors/$(errorInfo.'type')",
  title: "errorInfo.title,"
  status: errorInfo.status,
  detail: payload.error.description,
  timestamp: now()
}
Enter fullscreen mode Exit fullscreen mode

Every error, every endpoint, same format. The mobile team wrote 1 parser.


100 production-ready DataWeave patterns with tests: mulesoft-cookbook on GitHub


The Error Mapping Lookup

The errorMapping object maps Mule error type identifiers to HTTP semantics:

var errorInfo = errorMapping[payload.error.errorType.identifier]
  default { status: 500, title: "Internal Server Error", "type": "server-error" }
Enter fullscreen mode Exit fullscreen mode

errorType.identifier comes from Mule's error object — values like "HTTP:BAD_REQUEST", "HTTP:NOT_FOUND", "VALIDATION:INVALID_PAYLOAD".

The lookup errorMapping["HTTP:NOT_FOUND"] returns the mapped status and title. If the error type isn't in the mapping, default provides a 500 fallback.

Trap: Missing default Clause

Without default:

var errorInfo = errorMapping[payload.error.errorType.identifier]
Enter fullscreen mode Exit fullscreen mode

An unmapped error type (like "CUSTOM:BUSINESS_RULE") returns null. Your response:

{"type": null, "title": null, "status": null, "detail": "Business rule violated"}
Enter fullscreen mode Exit fullscreen mode

Technically valid JSON. Completely useless to the client. The mobile app shows "null" as the error title.

I hit this in production when a custom connector threw "CUSTOM:RATE_EXCEEDED" — an error type I hadn't mapped. The API returned a null-filled error response. The mobile app crashed trying to display null.title.

Rule: Always use default on error mapping lookups. The default should be a valid 500 response, not null.

The Reserved Word Trap

errorInfo.'type'   // Works — quoted field access
errorInfo.type     // Parse error — "type" is reserved in DataWeave
Enter fullscreen mode Exit fullscreen mode

type is a reserved keyword. When your error mapping uses type as a field name, you must access it with quotes: errorInfo.'type'. Without quotes, DataWeave throws a parse error.

I spent 20 minutes on this. The error message says "unexpected token" — it doesn't mention that type is reserved.

RFC 7807 Fields

Field Required Purpose
type Yes URI identifying the error category
title Yes Human-readable error title
status Yes HTTP status code
detail Yes Specific error description
instance No URI of the failing request
timestamp No When the error occurred
correlationId No Request trace ID

What I Do Now

  1. Every API project gets the error envelope pattern in the global error handler
  2. default on every mapping lookup — no exceptions
  3. Quoted access for type field
  4. I add correlationId from the Mule correlation ID for trace support
  5. Content-Type: application/problem+json (supported since Mule 4.4)

100 patterns with MUnit tests: github.com/shakarbisetty/mulesoft-cookbook

60-second video walkthroughs: youtube.com/@SanThaParv

Top comments (0)