2016-10-13 12:44:52 -04:00
# API styleguide
2016-10-13 13:38:38 -04:00
This styleguide recommends best practices for API development.
2016-10-13 12:44:52 -04:00
2016-10-13 13:35:57 -04:00
## Instance variables
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.
## Entities
Always use an [Entity] to present the endpoint's payload.
2020-03-18 14:09:35 -04:00
## Documentation
API endpoints must come with [documentation ](documentation/styleguide.md#api ), 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.
2016-10-13 13:35:57 -04:00
## Methods and parameters description
Every method must be described using the [Grape DSL ](https://github.com/ruby-grape/grape#describing-methods )
2019-09-18 14:06:14 -04:00
(see < https: / / gitlab . com / gitlab-org / gitlab / blob / master / lib / api / environments . rb >
2016-10-13 13:35:57 -04:00
for a good example):
- `desc` for the method summary. You should pass it a block for additional
details such as:
2020-02-03 13:08:46 -05:00
- 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._
2016-10-17 04:10:13 -04:00
- If the endpoint is deprecated, and if so, when will it be removed
2016-10-13 13:35:57 -04:00
2020-03-26 23:07:56 -04:00
- `params` for the method parameters. This acts as description,
2016-10-13 13:40:20 -04:00
[validation, and coercion of the parameters]
2016-10-13 13:35:57 -04:00
A good example is as follows:
```ruby
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
```
2020-03-26 23:07:56 -04:00
## Declared parameters
2016-10-13 12:44:52 -04:00
> Grape allows you to access only the parameters that have been declared by your
2020-03-26 23:07:56 -04:00
`params` block. It filters out the parameters that have been passed, but are not
2016-10-13 12:44:52 -04:00
allowed.
2019-01-24 01:52:33 -05:00
– < https: / / github . com / ruby-grape / grape # declared >
2016-10-13 12:44:52 -04:00
2020-03-26 23:07:56 -04:00
### Exclude parameters from parent namespaces
2016-10-13 12:44:52 -04:00
2019-07-08 23:28:41 -04:00
> By default `declared(params)`includes parameters that were defined in all
2016-10-13 12:44:52 -04:00
parent namespaces.
2019-01-24 01:52:33 -05:00
– < https: / / github . com / ruby-grape / grape # include-parent-namespaces >
2016-10-13 12:44:52 -04:00
2020-03-26 23:07:56 -04:00
In most cases you will want to exclude parameters from the parent namespaces:
2016-10-13 12:44:52 -04:00
```ruby
declared(params, include_parent_namespaces: false)
```
2019-08-22 04:50:31 -04:00
### When to use `declared(params)`
2016-10-13 12:44:52 -04:00
2020-03-26 23:07:56 -04:00
You should always use `declared(params)` when you pass the parameters hash as
2016-10-13 12:44:52 -04:00
arguments to a method call.
For instance:
```ruby
# bad
User.create(params) # imagine the user submitted `admin=1` ... :)
# good
User.create(declared(params, include_parent_namespaces: false).to_h)
```
>**Note:**
`declared(params)` return a `Hashie::Mash` object, on which you will have to
call `.to_h` .
2016-10-17 04:10:13 -04:00
But we can use `params[key]` directly when we access single elements.
2016-10-13 12:44:52 -04:00
For instance:
```ruby
# good
Model.create(foo: params[:foo])
```
2020-01-16 13:08:46 -05:00
## Using HTTP status helpers
For non-200 HTTP responses, use the provided helpers in `lib/api/helpers.rb` to ensure correct behaviour (`not_found!`, `no_content!` etc.). These will `throw` inside Grape and abort the execution of your endpoint.
For `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.
2019-09-16 11:06:26 -04:00
## Using API path helpers in GitLab Rails codebase
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.
For instance:
```haml
- endpoint = expose_path(api_v4_projects_issues_related_merge_requests_path(id: @project .id, issue_iid: @issue .iid))
```
2019-10-08 11:06:04 -04:00
## Internal API
The [internal API ](./internal_api.md ) is documented for internal use. Please keep it up to date so we know what endpoints
different components are making use of.
2019-09-18 14:06:14 -04:00
[Entity]: https://gitlab.com/gitlab-org/gitlab/blob/master/lib/api/entities.rb
2016-10-13 13:40:20 -04:00
[validation, and coercion of the parameters]: https://github.com/ruby-grape/grape#parameter-validation-and-coercion
2019-09-16 11:06:26 -04:00
[installing GitLab under a relative URL]: https://docs.gitlab.com/ee/install/relative_url.html
2020-03-03 10:08:08 -05:00
## Testing
When writing tests for new API endpoints, consider using a schema [fixture ](./testing_guide/best_practices.md#fixtures ) located in `/spec/fixtures/api/schemas` . You can `expect` a response to match a given schema:
```ruby
expect(response).to match_response_schema('merge_requests')
```