docs: rewrite JsonRpcBundle docs, add SDK docs, move them under docs/api
en/docs/api/rest-bundle/routing.md
new file +126
ā0
1
+
# Routing
2
+
3
+
## From `#[Route]` to a REST route
4
+
5
+
An RPC procedure method gets into REST when it has the `Symfony\Component\Routing\Attribute\Route` attribute. The attribute on the class is optional and sets a common path and name. Methods without `#[Route]` stay RPC-only.
6
+
7
+
| Part | Rule |
8
+
| --- | --- |
9
+
| Path | class path + `/` + method path; an empty method path gives the class path, both empty give `/` |
10
+
| Name | `ufo_rest_api_` + class name + `_` + method name |
11
+
| Class name | `name` from the class attribute; without it, the procedure alias from [`#[RPC\Info]`](/docs/api/json-rpc-bundle/add_rpc_service/info) in snake_case (`shopItems` ā `shop_items`) |
12
+
| Method name | `name` from the method attribute; without it, the PHP method name in snake_case (`createItem` ā `create_item`) |
13
+
| HTTP methods | `methods` from the method attribute; without them, `POST` |
14
+
| Other `#[Route]` options | `requirements`, `defaults`, `host` etc. are not used: only `path`, `name` and `methods` are read |
15
+
16
+
```php
17
+
#[RPC\Info('catalog')]
18
+
#[Route('/catalog', name: 'catalog')]
19
+
class CatalogApi implements IRpcService
20
+
{
21
+
#[Route('/items/{id}', name: 'item', methods: ['GET'])] // GET /rest/catalog/items/{id}
22
+
public function item(int $id): array {}
23
+
24
+
#[Route('/items')] // POST /rest/catalog/items
25
+
public function createItem(string $title): array {}
26
+
}
27
+
```
28
+
29
+
Path variables (`{id}`) are passed to the method as parameters with the same name; see [Request parameters](/docs/api/rest-bundle/requests).
30
+
31
+
:::warning
32
+
The path is not derived from the RPC method name automatically: without `#[Route]` the method is not available via REST, and an unknown path returns `404`.
33
+
:::
34
+
35
+
## Generated routes
36
+
37
+
For each REST method and API version two Symfony routes are created:
38
+
39
+
| Route | Path | HTTP methods | Purpose |
40
+
| --- | --- | --- | --- |
41
+
| `<name>_<version>` | `<path>`, for versions other than `v1`, `/<version><path>` | from the attribute | Method call |
42
+
| `<name>_<version>_method_not_allowed` | the same | any | Priority `-10`: a wrong HTTP method gets `405` rather than `404` |
43
+
44
+
Routes from the bundle's `config/router.yaml`:
45
+
46
+
| Route | Path | Purpose |
47
+
| --- | --- | --- |
48
+
| `ufo_rest_doc` | the import prefix | OpenAPI, `GET` |
49
+
| `ufo_rest_doc_ver` | `/{ver}` (`v\d+`) | OpenAPI for a version |
50
+
| `ufo_rest_doc_postman` | `/postman` | Postman |
51
+
| `ufo_rest_doc_postman_ver` | `/{ver}/postman` | Postman for a version |
52
+
| `ufo_rest_api_entrypoint` | `/{path}` | Catch-all entry point, priority `-100`: an unknown path returns `404` in the [error](/docs/api/rest-bundle/error_handling) format |
53
+
| `ufo_rest_api_entrypoint_ver` | `/{ver}/{path}` | The same for versions, priority `-90` |
54
+
55
+
`HEAD` is handled by `GET` routes. `OPTIONS` is not handled separately: for a method without `OPTIONS` in `methods` the response is `405`.
56
+
57
+
## Versions
58
+
59
+
Versions are defined by JsonRpcBundle: `#[RPC\Info(version: 2, removedMethods: [...])]` ([API versions](/docs/api/json-rpc-bundle/functionality/versions)). A version 2 procedure inherits the version 1 methods it does not override or remove.
60
+
61
+
| Version | Call | Documentation | Route name |
62
+
| --- | --- | --- | --- |
63
+
| `v1` (default) | `/rest/catalog/items/1` | `/rest`, `/rest/postman` | `..._v1` |
64
+
| `v2` | `/rest/v2/catalog/items/1` | `/rest/v2`, `/rest/v2/postman` | `..._v2` |
65
+
66
+
An unknown version returns `404`.
67
+
68
+
## API groups and multiple entry points
69
+
70
+
Import `config/router.yaml` separately for each entry point. `defaults.api_group` selects the [API group](/docs/api/json-rpc-bundle/functionality/groups); without it, the group is `general`. The URL prefix does not depend on the group name.
71
+
72
+
```yaml
73
+
# config/routes/ufo_rest_api.yaml
74
+
rest:
75
+
resource: ../../vendor/ufo-tech/rest-bundle/config/router.yaml
76
+
prefix: /rest
77
+
trailing_slash_on_root: false
78
+
79
+
rest_internal:
80
+
resource: ../../vendor/ufo-tech/rest-bundle/config/router.yaml
81
+
prefix: /internal
82
+
defaults: { api_group: internal }
83
+
trailing_slash_on_root: false
84
+
85
+
rest_partners:
86
+
resource: ../../vendor/ufo-tech/rest-bundle/config/router.yaml
87
+
prefix: /partners
88
+
name_prefix: partners_
89
+
defaults: { api_group: internal }
90
+
trailing_slash_on_root: false
91
+
```
92
+
93
+
```php
94
+
#[RPC\Info('catalog')]
95
+
#[RPC\APIGroups(['internal', 'public'], false)]
96
+
#[Route('/catalog', name: 'catalog')]
97
+
class CatalogApi implements IRpcService
98
+
{
99
+
#[Route('/list', name: 'list', methods: ['GET'])]
100
+
public function list(): array { return []; }
101
+
102
+
#[RPC\APIGroups(['internal'], false)]
103
+
#[Route('/price', name: 'price', methods: ['POST'])]
104
+
public function price(int $price): int { return $price; }
105
+
}
106
+
```
107
+
108
+
* Group membership of a method is defined by `#[RPC\APIGroups]`: the method attribute replaces the class attribute, `withDefault: true` adds `general`. `#[RPC\IgnoreApi]` excludes the method completely. For a method to appear in REST, `#[Route]` is required anyway.
109
+
* Each entry point has its own methods, versions, documentation and token provider.
110
+
* Route names get the group prefix: `internal_ufo_rest_doc`, `internal_ufo_rest_api_catalog_list_v1`. `name_prefix` goes after it: `internal_partners_ufo_rest_doc`.
111
+
* Routes of the `general` group also keep the old names as aliases: `ufo_rest_doc` ā `general_ufo_rest_doc`.
112
+
* Only the route defines the group: an `api_group` field in the query or body does not change it.
113
+
114
+
## Alongside RPC and other adapters
115
+
116
+
REST routes are registered through `Ufo\JsonRpcBundle\Routing\IApiRouteImport` (the `RestRouteImport` class), so groups and names are handled by the JsonRpcBundle route loader. RPC routes, REST routes and routes of other adapters implementing the same interface can be imported for the same groups in one file without name conflicts.
117
+
118
+
:::info
119
+
In 1.1ā1.2 this was done by the bundle's own `RestYamlFileLoader`; it was removed in 1.3 (see the [Changelog](/docs/api/rest-bundle/change_log)). Applications that only import `config/router.yaml` are not affected.
120
+
:::
121
+
122
+
## Troubleshooting
123
+
124
+
* **The method is not in REST**: check `#[Route]` on the method, the API group of the import, `#[RPC\IgnoreApi]` and the version's `removedMethods`.
125
+
* **`405` for an existing method**: the HTTP method is not in the attribute's `methods` (only `POST` by default).
126
+
* **Route names**: `bin/console debug:router | grep ufo_rest`.