Resources
Resources use the Rails router. The DSL mirrors Rails' resources and passes options through to Rails routing.
On top of routing, each resource is linked to a contract and included in exports.
Path and Namespace
The path passed to define determines two things:
- Mount point — where routes live (
/api/v1/posts) - Namespace — where Apiwork looks for controllers and contracts
Apiwork::API.define '/api/v1' do
resources :posts
end
# Path: /api/v1 maps to namespace Api::V1
# Controller: Api::V1::PostsController
# Contract: Api::V1::PostContract
# Representation: Api::V1::PostRepresentationThe conversion is straightforward: /api/v1 becomes Api::V1.
For APIs without a prefix:
Apiwork::API.define '/' do
resources :posts
end
# Routes at /posts
# No namespace prefixMultiple APIs
You can define multiple APIs, each completely independent:
# config/apis/api_v1.rb
Apiwork::API.define '/api/v1' do
resources :posts, only: [:index, :show]
end
# config/apis/api_v2.rb
Apiwork::API.define '/api/v2' do
resources :posts
resources :articles
endEach API has its own namespace with controllers, contracts, and representations.
Plural Resources
resources :postsGenerates five CRUD actions:
| Action | Method | Path |
|---|---|---|
| index | GET | /posts |
| show | GET | /posts/:id |
| create | POST | /posts |
| update | PATCH | /posts/:id |
| destroy | DELETE | /posts/:id |
Singular Resources
resource :accountFor resources where there's only one (like the current user's account):
| Action | Method | Path |
|---|---|---|
| show | GET | /account |
| create | POST | /account |
| update | PATCH | /account |
| destroy | DELETE | /account |
No index action, no :id in the path. The controller is still plural (AccountsController) — this is standard Rails resource behavior.
Limiting Actions
only
resources :posts, only: [:index, :show]Only generates the specified actions.
except
resources :posts, except: [:destroy]Generates all actions except the specified ones.
Nested Resources
resources :posts do
resources :comments
endGenerates routes like /posts/:post_id/comments and /posts/:post_id/comments/:id.
Contract Inference
Apiwork infers the contract from the resource name in singular form:
resources :posts # uses PostContract
resources :comments # uses CommentContract
resource :account # uses AccountContractTIP
If you have both resources :user and resources :users, they would both try to use UserContract. Use the contract: option to disambiguate:
resources :user, contract: 'current_user' # uses CurrentUserContract
resources :users # uses UserContractCustom Contract
The inferred contract can be overridden:
resources :posts, contract: 'public_post'
# Uses Api::V1::PublicPostContract
resources :posts, contract: 'admin/post'
# Uses Api::V1::Admin::PostContractCustom Controller
resources :posts, controller: 'articles'
# Uses Api::V1::ArticlesController
resources :posts, controller: 'admin/posts'
# Uses Api::V1::Admin::PostsControllerRouting Options
param
Changes the ID parameter name in routes:
resources :invoices, param: :number| Action | Path |
|---|---|
| show | /invoices/:number |
| update | /invoices/:number |
The controller receives the value as params[:number] instead of params[:id].
path
Changes the URL segment without changing the resource name:
resources :invoices, path: 'billing'| Action | Path |
|---|---|
| index | /billing |
| show | /billing/:id |
The controller and contract are still InvoicesController and InvoiceContract. Only the URL changes.
constraints
Restricts which requests match the route:
resources :invoices, constraints: { id: /\d+/ }Requests where :id is not numeric will not match. Works the same as Rails route constraints.
defaults
Sets default route parameters:
resources :invoices, defaults: { format: :json }with_options
Applies the same options to multiple resources:
Apiwork::API.define '/api/v1' do
with_options only: [:index, :show] do
resources :reports
resources :analytics
end
resources :invoices
endreports and analytics are read-only. invoices gets all five CRUD actions.
Options can be combined:
with_options only: [:index, :show], constraints: { id: /\d+/ } do
resources :invoices
resources :payments
endCustom Actions
Custom actions are added with member and collection blocks.
Member Actions
Member actions operate on a single resource (they have an :id):
resources :posts do
member do
patch :publish
patch :archive
get :preview
end
end| Action | Method | Path |
|---|---|---|
| publish | PATCH | /posts/:id/publish |
| archive | PATCH | /posts/:id/archive |
| preview | GET | /posts/:id/preview |
Collection Actions
Collection actions operate on the entire collection (no :id):
resources :posts do
collection do
get :search
post :bulk_create
delete :bulk_destroy
end
end| Action | Method | Path |
|---|---|---|
| search | GET | /posts/search |
| bulk_create | POST | /posts/bulk_create |
| bulk_destroy | DELETE | /posts/bulk_destroy |
HTTP Verbs
Available verbs: get, post, patch, put, delete
member do
get :preview # Read-only operation
patch :publish # Update state
post :duplicate # Create something new
delete :archive # Remove/archive
endShorthand
Multiple actions with the same verb:
member do
patch :publish, :archive, :approve
end
collection do
get :drafts, :published, :archived
endon: Parameter
Define member or collection actions without a block:
resources :posts do
get :preview, on: :member
get :search, on: :collection
patch :publish, :archive, on: :member
endEquivalent to wrapping in member do or collection do blocks.
Concerns
Concerns extract reusable routing patterns.
Defining a Concern
Apiwork::API.define '/api/v1' do
concern :auditable do
member do
get :audit_log
end
end
resources :posts, concerns: [:auditable]
resources :comments, concerns: [:auditable]
endBoth posts and comments now have a GET /posts/:id/audit_log and GET /comments/:id/audit_log endpoint.
Multiple Concerns
concern :auditable do
member do
get :audit_log
end
end
concern :searchable do
collection do
get :search
end
end
resources :posts, concerns: [:auditable, :searchable]Concerns with Nested Resources
concern :commentable do
resources :comments do
member do
patch :approve
patch :reject
end
collection do
get :pending
end
end
end
resources :posts, concerns: [:commentable]
resources :articles, concerns: [:commentable]Both posts and articles now have nested comment routes with approve, reject, and pending actions.
See also
- API::Base reference —
resources,resource,concern, and routing options