Resources
Resources are created using the Resource class, which is a transformation layer responsible for shaping a single domain object into a predictable JSON response structure.
It does not merely wrap data — it defines how raw data becomes API output.
A Resource:
- Accepts a single object (plain object, model instance, DTO, etc.)
- Controls how that object is serialized
- Wraps the transformed output inside a standardized
{ data: ... }envelope - Supports attaching additional top-level fields
- Can behave like a Promise (it is awaitable)
- Is designed to be extended for custom transformation logic
Think of it as the boundary between your internal data structures and your public API contract.
Instead of returning raw objects from your application layer, a Resource ensures:
- Response consistency
- Centralized formatting logic
- Extensibility without mutating original data
- Clean separation between domain logic and presentation logic
When extended, the data() method becomes the canonical place where transformation rules live.
Creating a Resource
import { Resource } from 'resora';
const user = { id: 1, name: 'John' };
const resource = new Resource(user);Accessing Raw Data
resource.data();Returns the original resource payload unless overridden.
{ "id": 1, "name": "John" }JSON Response Format
Calling .json() prepares a structured response:
resource.getBody();Produces:
{
"data": {
"id": 1,
"name": "John"
}
}Adding Additional Data
You may attach extra top-level fields:
resource.additional({ status: 'success' }).getBody();Result:
{
"data": {
"id": 1,
"name": "John"
},
"status": "success"
}additional() is chainable.
Metadata Customization
Resources also support metadata customization via with() and withMeta().
- Use
with()for class-level metadata hooks. - Use
withMeta()for typed fluent metadata chaining.
See the full guide in Writing Resources - Metadata APIs: with() vs withMeta().
Response Customization
You can also customize:
- Payload key casing via
preferredCase - JSON envelope via
responseStructure - Final outgoing transport response via
withResponse()
See:
Building a Response Object
const response = resource.response(res);This returns a response-compatible object. The structure is framework-agnostic.
Thenable Support (Async/Await)
Resource is promise-like.
const result = await resource;Resolves to:
{
"data": {
"id": 1,
"name": "John"
}
}This allows usage like:
return await new UserResource(user);Extending Resource
Resources are meant to be extended.
Custom Transformation
class UserResource extends Resource {
data() {
return {
id: this.id,
name: this.name,
custom: 'data',
};
}
}new UserResource({ id: 1, name: 'John' }).data();Result:
{
"id": 1,
"name": "John",
"custom": "data"
}Accessing Original Payload
Inside extended classes:
this.toArray()returns original payload- Properties are proxied (
this.id,this.name)
Chaining Still Works
Extended resources retain:
.json().additional().response()awaitsupport