-
Notifications
You must be signed in to change notification settings - Fork 24
OpenAPI Guide
Use OpenAPI Playground to see what documentation Rage::OpenAPI
generates without having to set up a project. Experiment with various tags and serializer combinations to understand how Rage::OpenAPI
works.
Rage::OpenAPI
is a lightweight solution that allows you to create and customize an OpenAPI specification for your application. To enable OpenAPI specification for an application, update your config.ru
file to mount the Rage::OpenAPI
component at the URL of your choice. For example:
map "/publicapi" do
run Rage::OpenAPI.application
end
Alternatively, Rage::OpenAPI
can also be mounted in config/routes.rb
:
Rage.routes.draw do
mount Rage::OpenAPI.application, at: "/publicapi"
end
Consider we have the following route definitions:
Rage.routes.draw do
namespace :api do
namespace :v1 do
resources :users, only: %i[index show create]
resources :photos, only: :index
end
namespace :v2 do
resources :users, only: :show
end
end
end
Launch the server using the rage s
command and visit localhost:3000/publicapi
to see the specification:

Currently, our specification is not very useful. All we do is display a list of endpoints the application exposes. Sometimes, this is what we are looking for, but most of the time, what we also want is to add some information to our specification and turn a faceless list of API endpoints into actual documentation.
One of the main concepts of Rage::OpenAPI
is limited scope. We believe that complex DSLs that attempt to implement the whole OpenAPI specification make no sense - at some point it becomes easier to manually create an OpenAPI document instead of learning a DSL, which will then create the OpenAPI document for you.
Instead, Rage::OpenAPI
aims to enhance the developer experience by focusing on specific tasks that API developers face. With Rage::OpenAPI
, customizations to your API specification can be made using YARD-style tags placed directly on action definitions inside controllers. Not only is this a very simple and natural way to document APIs, but it also allows you to simultaneously document your code, too.
There are two types of tags. Some tags, like @description
, can only be attached to an action within a controller. Others, like @deprecated
, can also be attached to a class. This way, all actions in the class together with all actions in child classes will become deprecated.
The simplest customization you can make is to add a summary - comment on your action to add a one-line summary to the specification.
class Api::V1::UsersController < ApplicationController
# Returns the list of all active non-admin users.
def index
end
end
Reload the page to see the updated specification:

@description
allows you to add a longer description for documentation purposes. The tag supports markdown, and, similar to other text tags, can be multi-line.
class Api::V1::UsersController < ApplicationController
# Returns the list of all active non-admin users.
# @description The API endpoint provides access to a list of
# registered users within the system. Only non-admin
# users are returned by this endpoint.
def show
end
end
The @version
and @title
tags can only be used once per API specification and allow setting the title
and version
properties on the info object.
The @internal
tag allows you to leave comments for other developers. Rage::OpenAPI
ignores this tag and doesn't put its contents into the specification:
class Api::V1::UsersController < ApplicationController
# @internal All changes to this action must first be approved by a principal engineer.
def create
end
end
With @deprecated
you can mark an action as deprecated:
class Api::V1::UsersController < ApplicationController
def index
end
# @deprecated
def create
end
end
Additionally, you can mark the whole class as deprecated. In such a case, make sure to place the tag inside the class without attaching it to an action:
class Api::V1::UsersController < ApplicationController
# @deprecated
def index
end
def create
end
end
Usually, Ruby developers place authentication logic in the before_action
callbacks. With Rage::OpenAPI
, you can specify the name of the before_action
used for authentication using the @auth
tag. For instance:
class ApplicationController
before_action :authenticate_by_token
# @auth authenticate_by_token
private
def authenticate_by_token
...
end
end
In this example, Rage::OpenAPI
will follow all applications of the authenticate_by_token
callback, take into account the skip_before_action
calls, and apply the corresponding security scheme to all necessary controller actions. By default, the scheme that corresponds with the authenticate_with_http_token method is used:
type: http
scheme: bearer
You can customize the security scheme definition by inlining a corresponding YAML entry:
class ApplicationController
before_action :authenticate_by_token
# @auth authenticate_by_token
# type: apiKey
# in: header
# name: X-API-Key
private
def authenticate_by_token
...
end
end
It is also possible to have multiple security schemes:
class ApplicationController
before_action :authenticate_by_user_token
before_action :authenticate_by_service_token
# @auth authenticate_by_user_token
# @auth authenticate_by_service_token
end
The optional second argument can be used to change the name of the security scheme:
class ApplicationController
before_action :authenticate_by_token
# @auth authenticate_by_token UserAuth
end
With Rage::OpenAPI
, there are three ways to specify the response schema.
For simple use cases, you can inline a YAML definition of the response into the tag:
class Api::V1::UsersController < ApplicationController
# @response { id: Integer, full_name: String }
def show
end
end
For the maximum flexibility, you can use shared references. Finally, Rage::OpenAPI
can automatically build the response schema based on ActiveRecord
models or Alba resources.
For example, let's say we have the following Alba resource:
class UserResource
include Alba::Resource
root_key :user
attributes :id, :name, :email
end
Pass the resource to the @response
tag to have Rage::OpenAPI
build the response schema:
class Api::V1::UsersController < ApplicationController
# @response UserResource
def show
end
end
The response schema Rage::OpenAPI
builds will look like this:
schema:
type: object
properties:
user:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
Most Alba features, including associations, key transformations, inheritance, and typed attributes, are supported. Use the []
or Array<>
to specify that the endpoint returns a collection:
class Api::V1::UsersController < ApplicationController
# @response Array<UserResource>
def index
end
end
Rage::OpenAPI
also takes namespaces into account, so in case you have the Api::V1::UserResource
and Api::V2::UserResource
classes, referencing UserResource
from Api::V2::UsersController
will pick Api::V2::UserResource
.
Additionally, in case the endpoint can have different responses, you can optionally pass the response code in the first argument:
class Api::V1::UsersController < ApplicationController
# @response 200 UserResource
# @response 404 { error_code: String }
def show
end
end
Response tags can also be global, in which case they will be applied to all actions of all child controllers:
class Api::V1::BaseController < ApplicationController
# @response 404 { status: "NOT_FOUND" }
# @response 500 { status: "ERROR", message: String }
end
The @request
tag is pretty similar to the @response
tag - it can accept an inline YAML, a shared reference, or an ActiveRecord
model. In the latter case, Rage::OpenAPI
will strip all internal attributes from the request, e.g. id
, created_at
, or type
.
class Api::V1::UsersController < ApplicationController
# @request User
def create
end
end
The @param
tag can be used to describe query parameters:
class Api::V1::UsersController < ApplicationController
# @param account_id The account the records are attached to
def index
end
end
By default, parameters are required. To mark a parameter as optional, use a ?
after the parameter name:
class Api::V1::UsersController < ApplicationController
# @param created_at? Filter records by creation date
def index
end
end
You can also specify the type of the parameter by enclosing it in {}
and providing it as a second argument:
class Api::V1::UsersController < ApplicationController
# @param is_active {Boolean} Filter records by active status
def index
end
end
Rage::OpenAPI
allows you to have a file with shared OpenAPI definitions that you can reference from the tags like @response
, @request
, or @param
. The file can either be in the YAML or JSON format and should have the root components
key.
For example, create the config/openapi_components.yml
file with the following content:
components:
schemas:
User:
type: object
properties:
id:
type: integer
name:
type: string
Then, reference the component inside the controller:
class Api::V1::UsersController < ApplicationController
# @response #/components/schemas/User
def show
end
end
There are two options you can use to limit the visibility of specific endpoints. The first is the @private
tag. You can use @private
to either hide single actions:
class Api::V1::UsersController < ApplicationController
def show
end
# @private
def create
end
end
or the entire class:
class Api::V1::UsersController < ApplicationController
# @private
def show
end
def create
end
end
Additionally, you can limit Rage::OpenAPI
to a specific namespace by passing it into the Rage::OpenAPI.application
call:
map "/publicapi" do
run Rage::OpenAPI.application(namespace: "Api::V2")
end
With this option, you can even have different specifications for different use cases:
map "/publicapi" do
run Rage::OpenAPI.application(namespace: "Api::Public")
end
map "/internalapi" do
use Rack::Auth::Basic
run Rage::OpenAPI.application(namespace: "Api::Internal")
end
Rage::OpenAPI
groups all endpoints by tags that it derives from controller names. For example, all actions from the Api::V1::UsersController
controller will be grouped under the v1/Users
tag.
You can customize this behavior with a custom tag resolver:
Rage.configure do
config.openapi.tag_resolver = proc do |controller, action, default_tag|
# ...
end
end
A custom tag resolver is a proc
that is passed to the config.openapi.tag_resolver
configuration. It is invoked for every endpoint Rage::OpenAPI
processes and accepts three arguments:
- the controller class;
- the action symbol;
- the original tag generated by
Rage::OpenAPI
;
The resolver should return a tag (or an array of tags) that will be assigned to the endpoint.