Wrappers
Wrappers structure the final response body. An adapter uses three wrapper types:
- Member wrapper - structures single-record responses (show, create, update)
- Collection wrapper - structures multi-record responses (index)
- Error wrapper - structures error responses
Each wrapper has two responsibilities:
- Shape - defines the response shape for introspection
- Wrap - transforms data into the final response body
Member Wrappers
Member wrappers inherit from Adapter::Wrapper::Member::Base:
ruby
class MyMemberWrapper < Adapter::Wrapper::Member::Base
shape do
reference(root_key.singular.to_sym, to: data_type)
object?(:meta)
metadata_type_names.each { |type_name| merge(type_name) }
end
def wrap
{
root_key.singular.to_sym => data,
meta: meta.presence,
**metadata,
}.compact
end
endAvailable Attributes
| Attribute | Description |
|---|---|
data | The serialized record |
root_key | Access to singular/plural key names |
meta | Custom metadata from controller |
metadata | Capability metadata (includes, etc.) |
Collection Wrappers
Collection wrappers inherit from Adapter::Wrapper::Collection::Base:
ruby
class MyCollectionWrapper < Adapter::Wrapper::Collection::Base
shape do
array(root_key.plural.to_sym) do |array|
array.reference(data_type)
end
object?(:meta)
metadata_type_names.each { |type_name| merge(type_name) }
end
def wrap
{
root_key.plural.to_sym => data,
meta: meta.presence,
**metadata,
}.compact
end
endAvailable Attributes
Same as member wrappers, plus:
| Attribute | Description |
|---|---|
data | Array of serialized records |
metadata | Capability metadata (pagination, etc.) |
Error Wrappers
Error wrappers inherit from Adapter::Wrapper::Error::Base:
ruby
class MyErrorWrapper < Adapter::Wrapper::Error::Base
shape do
extends(data_type)
end
def wrap
data
end
endThe Shape DSL
The shape block defines the response shape for introspection. Inside the block:
Available Methods
All type DSL methods from API::Object:
| Method | Purpose |
|---|---|
string, string? | String field (required/optional) |
integer, integer? | Integer field |
boolean, boolean? | Boolean field |
object, object? | Nested object |
array, array? | Array field |
reference, reference? | Reference to another type |
extends | Inherit from another type |
merge | Include properties from a named type |
Available Helpers
| Helper | Description |
|---|---|
root_key | Resource root key (has .singular and .plural) |
data_type | Type name from serializer |
metadata_type_names | Auto-generated type names from capability operations |
metadata_type_names
The metadata_type_names array contains auto-generated fragment type names from capability operations that define a metadata_shape. Iterate over them with merge to include capability metadata fields (pagination, filtering, etc.) in the response type.
Example: JSON:API Wrapper
ruby
class JsonApiMemberWrapper < Adapter::Wrapper::Member::Base
shape do
object(:data) do |object|
object.string(:type)
object.string(:id)
object.reference(:attributes, to: data_type)
end
end
def wrap
{
data: {
type: root_key.singular,
id: data[:id].to_s,
attributes: data.except(:id)
}
}
end
endExample: Envelope Wrapper
ruby
class EnvelopeMemberWrapper < Adapter::Wrapper::Member::Base
shape do
literal(:success, value: true)
reference(:data, to: data_type)
object?(:meta)
metadata_type_names.each { |type_name| merge(type_name) }
end
def wrap
{
success: true,
data: data,
meta: meta.presence,
**metadata,
}.compact
end
endUsing Custom Wrappers
Custom wrappers are registered in the adapter:
ruby
class MyAdapter < Apiwork::Adapter::Base
adapter_name :my
member_wrapper MyMemberWrapper
collection_wrapper MyCollectionWrapper
error_wrapper MyErrorWrapper
end