api_styleguide.md 3.91 KB
Newer Older
Rémy Coutable's avatar
Rémy Coutable committed
1 2
# API styleguide

Rémy Coutable's avatar
Rémy Coutable committed
3
This styleguide recommends best practices for API development.
Rémy Coutable's avatar
Rémy Coutable committed
4

5 6 7 8 9 10 11 12 13 14 15 16
## 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.

## Methods and parameters description

Every method must be described using the [Grape DSL](https://github.com/ruby-grape/grape#describing-methods)
17
(see <https://gitlab.com/gitlab-org/gitlab/blob/master/lib/api/environments.rb>
18 19 20 21 22
for a good example):

- `desc` for the method summary. You should pass it a block for additional
  details such as:
  - The GitLab version when the endpoint was added
Rémy Coutable's avatar
Rémy Coutable committed
23
  - If the endpoint is deprecated, and if so, when will it be removed
24

Rémy Coutable's avatar
Rémy Coutable committed
25 26
- `params` for the method params. This acts as description,
  [validation, and coercion of the parameters]
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

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
```

Rémy Coutable's avatar
Rémy Coutable committed
46 47 48 49 50 51
## Declared params

> Grape allows you to access only the parameters that have been declared by your
`params` block. It filters out the params that have been passed, but are not
allowed.

52
<https://github.com/ruby-grape/grape#declared>
Rémy Coutable's avatar
Rémy Coutable committed
53

54
### Exclude params from parent namespaces
Rémy Coutable's avatar
Rémy Coutable committed
55

56
> By default `declared(params)`includes parameters that were defined in all
Rémy Coutable's avatar
Rémy Coutable committed
57 58
parent namespaces.

59
<https://github.com/ruby-grape/grape#include-parent-namespaces>
Rémy Coutable's avatar
Rémy Coutable committed
60 61 62 63 64 65 66

In most cases you will want to exclude params from the parent namespaces:

```ruby
declared(params, include_parent_namespaces: false)
```

67
### When to use `declared(params)`
Rémy Coutable's avatar
Rémy Coutable committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

You should always use `declared(params)` when you pass the params hash as
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`.

Rémy Coutable's avatar
Rémy Coutable committed
86
But we can use `params[key]` directly when we access single elements.
Rémy Coutable's avatar
Rémy Coutable committed
87 88 89 90 91 92 93 94

For instance:

```ruby
# good
Model.create(foo: params[:foo])
```

95 96 97 98 99 100
## 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.

101 102 103 104 105 106 107 108 109 110 111 112
## 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))
```

113 114 115 116 117
## 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.

118
[Entity]: https://gitlab.com/gitlab-org/gitlab/blob/master/lib/api/entities.rb
Rémy Coutable's avatar
Rémy Coutable committed
119
[validation, and coercion of the parameters]: https://github.com/ruby-grape/grape#parameter-validation-and-coercion
120
[installing GitLab under a relative URL]: https://docs.gitlab.com/ee/install/relative_url.html