Skip to content

Commit 7bd6967

Browse files
authored
Merge pull request #54 from dotkernel/issue-53
Issue #53: Created `OpenAPI` documentation
2 parents 2279407 + dc566a2 commit 7bd6967

File tree

9 files changed

+637
-0
lines changed

9 files changed

+637
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Generating the documentation file
2+
3+
> Make sure that in `src/App/src/OpenAPI.php`, on the line with `#[OA\Server` the value of `url` is set to the of URL of
4+
> your instance of **Dotkernel API**.
5+
6+
Using your terminal, move to the root directory of your project.
7+
8+
Dotkernel API stores the OpenAPI attributes in the `src` directory, so that's the path we will use for generating the
9+
static documentation file.
10+
11+
## Methods of generating documentation file
12+
13+
### Without saving it to a file
14+
15+
```shell
16+
./vendor/bin/openapi ./src
17+
```
18+
19+
This will output the generated content to the terminal.
20+
21+
### Place it in a custom location
22+
23+
```shell
24+
./vendor/bin/openapi ./src --output public/openapi.yaml
25+
```
26+
27+
This will place the generated file `openapi.yaml` in the `public` directory.
28+
29+
### Specify OpenAPI version
30+
31+
Supported OpenAPI versions are `3.0.0` and `3.1.0`, `3.0.0` being the default version.
32+
33+
The below command will specify both the output location and the OpenAPI version:
34+
35+
```shell
36+
./vendor/bin/openapi ./src --version 3.1.0
37+
```
38+
39+
### Specify output file format
40+
41+
Supported file formats are `yaml` and `json`, `yaml` being the default format.
42+
43+
The below command will specify the output location and `zircote/swagger-php` will determine the file format:
44+
45+
```shell
46+
./vendor/bin/openapi ./src --output public/openapi.json
47+
```
48+
49+
Or be specific about the format by appending the `--format` argument:
50+
51+
```shell
52+
./vendor/bin/openapi ./src --output public/openapi.json --format json
53+
```
54+
55+
These will place the generated file `openapi.json` in the `public` directory.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Getting help
2+
3+
- consult the OpenAPI [specs](https://spec.openapis.org/oas/latest.html) for a complete
4+
reference of the presented objects
5+
- see more examples of OpenAPI object representations in `zircote/swagger-php`'s
6+
[GitHub repository](https://github.com/zircote/swagger-php/tree/master/Examples)
7+
- consult `zircote/swagger-php`'s
8+
[online documentation](http://zircote.github.io/swagger-php/guide/generating-openapi-documents.html) or run the
9+
following command to see their help page:
10+
11+
```shell
12+
./vendor/bin/openapi --help
13+
```
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# Initialized OpenAPI components
2+
3+
Below you will find details on some prepopulated OpenAPI components we added to Dotkernel API.
4+
5+
## OA\Info
6+
7+
Defined in `src/App/src/OpenAPI.php`, this object provides general info about the API:
8+
9+
- `version`: API version (example: `1.0.0`)
10+
- `title`: title shown in the UI (example: `Dotkernel API`)
11+
12+
For more info, see [this page](https://spec.openapis.org/oas/latest.html#info-object).
13+
14+
## OA\Server
15+
16+
Defined in `src/App/src/OpenAPI.php`, this object provides API server entries:
17+
18+
- `url`: API server URL (example: `https://api.example.com` - use no trailing slash!)
19+
- `description`: describes the purpose of the server (example: `Dev`, `Staging`, `Production` or even `Auth` if you use
20+
a separate authentication server)
21+
22+
You can have multiple `Server` definitions, one for each of your Dotkernel API instances.
23+
24+
For more info, see [this page](https://spec.openapis.org/oas/latest.html#server-object).
25+
26+
## OA\SecurityScheme
27+
28+
Defined in `src/App/src/OpenAPI.php`, you will find an object for the `AuthToken` security header:
29+
30+
- `securityScheme`: the name of the security scheme - you will provide this to indicate that an endpoint is protected
31+
- `type`: whether it's an API key, an authorization header etc
32+
- `in`: indicates where the scheme is applied (`query`/`header`/`cookie`)
33+
- `bearerFormat`: a hint to the client to identify how the bearer token is formatted
34+
- `scheme`: the name of the authorization scheme to be used
35+
36+
And another object for the `ErrorReportingToken` security token:
37+
38+
- `securityScheme`: the name of the security scheme - you will provide this to indicate that an endpoint is protected
39+
- `type`: whether it's an API key, an authorization header etc
40+
- `in`: indicates where the scheme is applied (`query`/`header`/`cookie`)
41+
- `name`: the name of the header
42+
43+
For more info, see [this page](https://spec.openapis.org/oas/latest.html#security-scheme-object).
44+
45+
## OA\ExternalDocumentation
46+
47+
Defined in `src/App/src/OpenAPI.php`, in this object we provide the following details:
48+
49+
- `description`: describes the purpose of the document
50+
- `url`: external documentation URL
51+
52+
For more info, see [this page](https://spec.openapis.org/oas/latest.html#external-documentation-object).
53+
54+
## OA\Schema
55+
56+
Schemas are OpenAPI objects describing an object or collection of objects existing in your project.
57+
58+
### Schemas describing objects
59+
60+
In order to describe an object (entity) you will need to transform in into a schema.
61+
62+
Object:
63+
64+
```php
65+
<?php
66+
67+
declare(strict_types=1);
68+
69+
namespace Api\User\Entity;
70+
71+
use Api\App\Entity\AbstractEntity;
72+
use Api\App\Entity\RoleInterface;
73+
use Api\App\Entity\TimestampsTrait;
74+
use Doctrine\ORM\Mapping as ORM;
75+
76+
class UserRole extends AbstractEntity implements RoleInterface
77+
{
78+
use TimestampsTrait;
79+
80+
#[ORM\Column(name: "name", type: "string", length: 20, unique: true)]
81+
protected ?string $name = null;
82+
83+
// methods
84+
}
85+
```
86+
87+
Schema:
88+
89+
```php
90+
<?php
91+
92+
declare(strict_types=1);
93+
94+
namespace Api\User;
95+
96+
use Api\User\Entity\UserRole;
97+
use OpenApi\Attributes as OA;
98+
99+
...
100+
101+
/**
102+
* @see UserRole
103+
*/
104+
#[OA\Schema(
105+
schema: 'UserRole',
106+
properties: [
107+
new OA\Property(property: 'uuid', type: 'string', example: '1234abcd-abcd-4321-12ab-123456abcdef'),
108+
new OA\Property(property: 'name', type: 'string', example: UserRole::ROLE_USER),
109+
new OA\Property(
110+
property: '_links',
111+
properties: [
112+
new OA\Property(
113+
property: 'self',
114+
properties: [
115+
new OA\Property(
116+
property: 'href',
117+
type: 'string',
118+
example: 'https://example.com/user/role/1234abcd-abcd-4321-12ab-123456abcdef',
119+
),
120+
],
121+
type: 'object',
122+
),
123+
],
124+
type: 'object',
125+
),
126+
],
127+
type: 'object',
128+
)]
129+
```
130+
131+
Then, when generating the documentation file, `OpenAPI` will transform it into the specified format (**json**/**yaml**).
132+
133+
```yaml
134+
UserRole:
135+
properties:
136+
uuid:
137+
type: string
138+
example: 1234abcd-abcd-4321-12ab-123456abcdef
139+
name:
140+
type: string
141+
example: user
142+
_links:
143+
properties:
144+
self:
145+
properties:
146+
href:
147+
type: string
148+
example: 'https://example.com/user/role/1234abcd-abcd-4321-12ab-123456abcdef'
149+
type: object
150+
type: object
151+
type: object
152+
```
153+
154+
### Schemas describing collections of objects
155+
156+
Collections of objects are just as easy to describe in `OpenAPI` as they are in PHP.
157+
158+
PHP collection:
159+
160+
```php
161+
<?php
162+
163+
declare(strict_types=1);
164+
165+
namespace Api\User\Collection;
166+
167+
use Api\App\Collection\ResourceCollection;
168+
169+
class UserRoleCollection extends ResourceCollection
170+
{
171+
}
172+
```
173+
174+
Schema:
175+
176+
```php
177+
#[OA\Schema(
178+
schema: 'UserRoleCollection',
179+
properties: [
180+
new OA\Property(
181+
property: '_embedded',
182+
properties: [
183+
new OA\Property(
184+
property: 'roles',
185+
type: 'array',
186+
items: new OA\Items(
187+
ref: '#/components/schemas/UserRole',
188+
),
189+
),
190+
],
191+
type: 'object',
192+
),
193+
],
194+
type: 'object',
195+
allOf: [
196+
new OA\Schema(ref: '#/components/schemas/Collection'),
197+
],
198+
)]
199+
```
200+
201+
Using `ref: '#/components/schemas/UserRole',` in our code, we instruct `OpenAPI` to grab the existing schema `UserRole`
202+
(not the entity, but the schema) that we just described earlier. This way we do not need to repeat code by describing
203+
again the same object and any future modifications will happen in only one place.
204+
205+
Then, when generating the documentation file, `OpenAPI` will transform it into the specified format (**json**/**yaml**).
206+
207+
```php
208+
UserRoleCollection:
209+
type: object
210+
allOf:
211+
-
212+
$ref: '#/components/schemas/Collection'
213+
-
214+
properties:
215+
_embedded:
216+
properties:
217+
roles:
218+
type: array
219+
items: { $ref: '#/components/schemas/UserRole' }
220+
type: object
221+
type: object
222+
```
223+
224+
> Make sure that in `src/App/src/OpenAPI.php`, on the line with `#[OA\Server` the value of `url` is set to the of URL of
225+
> your instance of **Dotkernel API**.
226+
>
227+
> You can add multiple servers (for staging, production etc) by duplicating the existing one.
228+
229+
For more info, see [this page](https://spec.openapis.org/oas/latest.html#schema).
230+
231+
### Common schemas
232+
233+
We provided some schemas that are reusable across the entire project. They are defined in `src/App/src/OpenAPI.php`:
234+
235+
- `#/components/schemas/Collection`: provides the default **HAL** structure to all the collections extending it
236+
- `#/components/schemas/ErrorMessage`: describes an operation that resulted in an error - may contain multiple messages
237+
- `#/components/schemas/InfoMessage`: describes an operation that completed successfully - may contain multiple messages
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# OpenAPI documentation
2+
3+
In order to provide an interactive documentation, Dotkernel API implemented
4+
[zircote/swagger-php](https://github.com/zircote/swagger-php).
5+
6+
Using this library, developers are able to automatically generate documentation files that later can be used to provide
7+
a comprehensive overview of the available endpoints, all the details on the requests that it can receive and the
8+
responses these can return.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Rendering the documentation file
2+
3+
At this step, you only have a static documentation file. You will need an interface that can render it so that you will
4+
be able to interact with your Dotkernel API.
5+
6+
In order to do this, we recommend using either of:
7+
8+
- [swagger-api/swagger-ui](https://github.com/swagger-api/swagger-ui)
9+
- [Redocly/redoc](https://github.com/Redocly/redoc)
10+
11+
## Using Swagger UI
12+
13+
Navigate to the `public` directory of your instance of Dotkernel API and create an HTML (you can call it `swagger.html`,
14+
the name is up to you) and place the following HTML content in it:
15+
16+
```html
17+
<!DOCTYPE html>
18+
<html lang="en">
19+
<head>
20+
<meta charset="utf-8" />
21+
<meta name="viewport" content="width=device-width, initial-scale=1" />
22+
<meta name="description" content="Dotkernel API Documentation" />
23+
<title>Dotkernel API Documentation</title>
24+
<link rel="stylesheet" href="https://unpkg.com/[email protected]/swagger-ui.css" />
25+
</head>
26+
<body>
27+
<div id="swagger-ui"></div>
28+
<script src="https://unpkg.com/[email protected]/swagger-ui-bundle.js" crossorigin></script>
29+
<script>
30+
window.onload = () => {
31+
window.ui = SwaggerUIBundle({url: 'PATH_TO_YOUR_OPENAPI_FILE', dom_id: '#swagger-ui'});
32+
};
33+
</script>
34+
</body>
35+
</html>
36+
```
37+
38+
Make sure that you replace `PATH_TO_YOUR_OPENAPI_FILE` with the relative path to your documentation file
39+
(openapi.json/openapi.yaml). The line should look similar to this:
40+
41+
```js
42+
window.ui = SwaggerUIBundle({url: './openapi.yaml', dom_id: '#swagger-ui'});
43+
```
44+
45+
Using your browser, open a new tab and type in the URL of your instance of Dotkernel API and append `/swagger.html` to
46+
it. You should see the Redoc interface with your documentation file loaded in it. From here, you can inspect each
47+
endpoint, see it's URL, check if it needs authentication, the request payload (if any) and the possible response(s).
48+
49+
## Using Redoc
50+
51+
Navigate to the `public` directory of your instance of Dotkernel API and create an HTML (you can call it `redoc.html`,
52+
the name is up to you) and place the following HTML content in it:
53+
54+
```html
55+
<!DOCTYPE html>
56+
<html lang="en">
57+
<head>
58+
<meta charset="utf-8" />
59+
<meta name="viewport" content="width=device-width, initial-scale=1" />
60+
<meta name="description" content="Dotkernel API Documentation" />
61+
<title>Dotkernel API Documentation</title>
62+
<script src="https://cdn.jsdelivr.net/npm/redoc@latest/bundles/redoc.standalone.js"></script>
63+
</head>
64+
<body>
65+
<div id="redoc-container"></div>
66+
<script>
67+
Redoc.init('PATH_TO_YOUR_OPENAPI_FILE', {}, document.getElementById('redoc-container'));
68+
</script>
69+
</body>
70+
</html>
71+
```
72+
73+
Make sure that you replace `PATH_TO_YOUR_OPENAPI_FILE` with the relative path to your documentation file
74+
(openapi.json/openapi.yaml). The line should look similar to this:
75+
76+
```js
77+
Redoc.init('./openapi.yaml', {}, document.getElementById('redoc-container'));
78+
```
79+
80+
Using your browser, open a new tab and type in the URL of your instance of Dotkernel API and append `/redoc.html` to it.
81+
You should see the Redoc interface with your documentation file loaded in it. From here, you can inspect each endpoint,
82+
see it's URL, check if it needs authentication, the request payload (if any) and the possible response(s).

0 commit comments

Comments
 (0)