JSON API to Backbone JSON Converter
Convert JSON:API formatted responses to Backbone.js-friendly flat JSON. Resolves included resources, flattens attributes, and embeds relationships.
About
The JSON:API specification enforces a compound document structure where resources are split across data and included arrays, with relationships expressed as type+id linkage objects. Backbone.js models and collections expect flat attribute hashes. Manually denormalizing these responses introduces bugs: missed includes produce NULL nested objects, circular relationships cause infinite loops, and polymorphic collections silently drop records when the type key is ignored. This converter resolves every relationship linkage against the included pool, flattens attributes to the root level, and detects reference cycles using a visited-set algorithm. It handles single-resource documents, resource-collection documents, and sparse fieldsets without data loss.
Limitations: this tool operates on static JSON text. It does not fetch remote URLs or handle server-sent streaming responses. Deeply nested circular relationships are detected and truncated with a [Circular] marker rather than causing a stack overflow. The maximum practical input size is approximately 50MB depending on browser memory. For payloads exceeding 500KB, conversion runs in a Web Worker to avoid UI freezing.
Formulas
The denormalization algorithm constructs an include-map M and recursively resolves each resource R:
For each resource in data (or the single resource object):
Relationship resolution per key k:
Cycle detection: before recursing into any resource, the composite key type:id is checked against visited (a Set). If present, a [Circular] marker replaces the nested object, preventing infinite recursion. The visited set is scoped per resolution path, not globally, allowing the same resource to appear in sibling branches.
In reference mode, instead of embedding, the algorithm outputs: k_id = linkage.id (for to-one) or k_ids = [linkage0.id, linkage1.id, ...] (for to-many).
Reference Data
| JSON:API Field | Location in Source | Backbone Output Mapping | Notes |
|---|---|---|---|
| data.id | Top-level resource | id (root key) | Always preserved as string |
| data.type | Top-level resource | _type (optional) | Included if "Preserve type" enabled |
| data.attributes.* | Nested in resource | Flattened to root keys | Key names unchanged |
| data.relationships.X.data | Linkage object | Embedded object or X_id | Mode: embed vs. reference |
| data.relationships.X.data[] | Linkage array | Array of objects or X_ids | Plural relationships |
| data.links | Resource links | _links (optional) | Only if "Preserve links" enabled |
| data.meta | Resource meta | _meta (optional) | Only if "Preserve meta" enabled |
| included[] | Top-level array | Resolved into relationships | Lookup by type:id |
| included[].attributes | Included resource | Flattened into nested object | Recursive resolution |
| included[].relationships | Included resource | Recursively resolved | Cycle detection applied |
| jsonapi | Top-level | Discarded | Server metadata not relevant to models |
| errors | Top-level | Passed through as-is | Error responses are not converted |
| links (top-level) | Document links | _documentLinks (optional) | Pagination links etc. |
| meta (top-level) | Document meta | _documentMeta (optional) | Total counts, cursors etc. |
| Null relationship | data: null | NULL | Preserved as null |
| Empty to-many | data: [] | Empty array [] | Preserved as empty array |
| Polymorphic to-many | Mixed type in array | Mixed embedded objects | Each resolved by own type |
| Missing include | Linkage with no match | { id, _type } stub | Warning emitted in console |