- Instance variables
- Methods and parameters description
- Declared parameters
- Using HTTP status helpers
- Using API path helpers in GitLab Rails codebase
- Internal API
This styleguide recommends best practices for API development.
Please do not use instance variables, there is no need for them (we don’t need to access them as we do in Rails views), local variables are fine.
Always use an Entity to present the endpoint’s payload.
API endpoints must come with documentation, unless it is internal or behind a feature flag. The docs should be in the same merge request, or, if strictly necessary, in a follow-up with the same milestone as the original merge request.
Every method must be described using the Grape DSL (see https://gitlab.com/gitlab-org/gitlab/blob/master/lib/api/environments.rb for a good example):
descfor the method summary. You should pass it a block for additional details such as:
- The GitLab version when the endpoint was added. If it is behind a feature flag, mention that instead: This feature is gated by the :feature_flag_symbol feature flag.
- If the endpoint is deprecated, and if so, when will it be removed
paramsfor the method parameters. This acts as description, validation, and coercion of the parameters
A good example is as follows:
desc 'Get all broadcast messages' do detail 'This feature was introduced in GitLab 8.12.' success Entities::BroadcastMessage end params do optional :page, type: Integer, desc: 'Current page number' optional :per_page, type: Integer, desc: 'Number of messages per page' end get do messages = BroadcastMessage.all present paginate(messages), with: Entities::BroadcastMessage end
Grape allows you to access only the parameters that have been declared by your
paramsblock. It filters out the parameters that have been passed, but are not allowed.
declared(params)includes parameters that were defined in all parent namespaces.
In most cases you will want to exclude parameters from the parent namespaces:
declared(params, include_parent_namespaces: false)
You should always use
declared(params) when you pass the parameters hash as
arguments to a method call.
# bad User.create(params) # imagine the user submitted `admin=1`... :) # good User.create(declared(params, include_parent_namespaces: false).to_h)
Hashie::Mashobject, on which you will have to call
But we can use
params[key] directly when we access single elements.
# good Model.create(foo: params[:foo])
For non-200 HTTP responses, use the provided helpers in
lib/api/helpers.rb to ensure correct behaviour (
no_content! etc.). These will
throw inside Grape and abort the execution of your endpoint.
DELETE requests, you should also generally use the
destroy_conditionally! helper which by default returns a
204 No Content response on success, or a
412 Precondition Failed response if the given
If-Unmodified-Since header is out of range. This helper calls
#destroy on the passed resource, but you can also implement a custom deletion method by passing a block.
Because we support installing GitLab under a relative URL, one must take this
into account when using API path helpers generated by Grape. Any such API path
helper usage must be in wrapped into the
expose_path helper call.
- endpoint = expose_path(api_v4_projects_issues_related_merge_requests_path(id: @project.id, issue_iid: @issue.iid))
The internal API is documented for internal use. Please keep it up to date so we know what endpoints different components are making use of.
When writing tests for new API endpoints, consider using a schema fixture located in
/spec/fixtures/api/schemas. You can
expect a response to match a given schema: