Controller
Mixin for API controllers that provides request validation and response helpers.
Include in controllers to access #contract, #expose, and #expose_error. Automatically validates requests against the contract before actions run.
Example: Basic controller
class InvoicesController < ApplicationController
include Apiwork::Controller
def index
expose Invoice.all
end
def show
invoice = Invoice.find(params[:id])
expose invoice
end
def create
invoice = Invoice.create(contract.body[:invoice])
expose invoice
end
endClass Methods
.skip_contract_validation!
.skip_contract_validation!(only: nil, except: nil)
Skips contract validation for specified actions.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
except | Array<Symbol> | Skip for all except these actions. | |
only | Array<Symbol> | Skip only for these actions. |
Example: Skip for specific actions
skip_contract_validation! only: [:ping, :status]Example: Skip for all actions
skip_contract_validation!Instance Methods
#context
#context
The context for this controller.
Passed to representations during serialization. Override to provide current user, permissions, locale, or feature flags.
Returns
Hash
Example: Provide current user context
def context
{ current_user: current_user }
endExample: Access context in representation
class InvoiceRepresentation < Apiwork::Representation::Base
attribute :editable, type: :boolean
def editable
context[:current_user].admin?
end
end#contract
#contract
The contract for this controller.
Contains parsed query parameters and request body with type coercion applied. Access parameters via Contract::Base#query and Contract::Base#body.
Returns
See also
Example: Access parsed parameters
def create
invoice = Invoice.new(contract.body)
# contract.body contains validated, coerced params
endExample: Check for specific parameters
def index
if contract.query[:include]
# handle include parameter
end
end#expose
#expose(data, meta: {}, status: nil)
Exposes data as an API response.
When a representation is linked via Contract::Base.representation, data is serialized through the representation. Otherwise, data is rendered as-is. Key transformation is applied according to the API's API::Base.key_format.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | Object, Array | The record(s) to expose. | |
meta | Hash | {} | The metadata to include in response (pagination, etc.). |
status | Symbol, Integer, nil | nil | The HTTP status (:ok, or :created for create action). |
See also
Example: Expose a single record
def show
invoice = Invoice.find(params[:id])
expose invoice
endExample: Expose a collection with metadata
def index
invoices = Invoice.all
expose invoices, meta: { total: invoices.count }
endExample: Custom status
def create
invoice = Invoice.create(contract.body[:invoice])
expose invoice, status: :created
end#expose_error
#expose_error(code_key, detail: nil, path: nil, meta: {})
Exposes an error response using a registered error code.
Defaults to I18n lookup when detail is not provided.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
code_key | Symbol | The registered error code (:not_found, :unauthorized, etc.). | |
detail | String, nil | nil | The custom error message (uses I18n lookup if nil). |
meta | Hash | {} | The additional metadata to include. |
path | Array<String, Symbol>, nil | nil | The JSON path to the error. |
See also
Example: Not found error
def show
invoice = Invoice.find_by(id: params[:id])
return expose_error :not_found unless invoice
expose invoice
endExample: With custom message
expose_error :forbidden, detail: 'You cannot access this invoice'