Skip to content

Commit 1dec6de

Browse files
authored
Introduced API annotations with the OPENAPI standard. (#134)
* rebase conflict: in .github/workflows/ci.yml fixed * init: OPENAPI with swagger-php Signed-off-by: fenn-cs <[email protected]> * added swagger ui Signed-off-by: fenn-cs <[email protected]> * initial : added endpoint annotations and openapi related documentation Signed-off-by: fenn-cs <[email protected]> * ran phpcbf to fix codesniffer issues in annotations Signed-off-by: fenn-cs <[email protected]> * fixed failing tests due to openapi annotations Signed-off-by: fenn-cs <[email protected]>
1 parent 8937e1e commit 1dec6de

File tree

7 files changed

+467
-1
lines changed

7 files changed

+467
-1
lines changed

.github/CONTRIBUTING.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,50 @@ have a chance of keeping on top of things:
6767
11. Together with your reviewer, polish your changes until they are ready to be
6868
merged.
6969

70+
## API Documentation with Swagger
71+
72+
Controllers are annotated with the [`OpenAPI`](https://swagger.io/docs/specification/about/) specification using the `PHPDoc` implementation from [zircote/swagger-php](https://github.com/zircote/swagger-php).
73+
74+
If you add or modify existing annotations, you should run `composer generate-openapi` to have the updated version of the API Docs.
75+
76+
77+
### Details on `composer generate-openapi`
78+
79+
`composer generate-openapi` basically runs `vendor/bin/openapi -o docs/swagger/openapi.json --format json src"` defined in the scripts section of `composer.json` which inturn generates the `OpenAPI` specification file `openapi.json` in the `docs/swagger` directory and then copies the documentation and `swagger-ui` files to `public/docs`.
80+
81+
82+
### Swagger UI
83+
84+
[Swagger UI](https://github.com/swagger-api/swagger-ui) is used to visualize generated `OpenAPI` documentation and is served at `{root-url}/docs` for example `localhost:8000/docs`.
85+
86+
#### Updating Swagger UI
87+
88+
We use`swagger-ui-dist` which is the compiled version of swagger UI for server side projects. It's simply a copy of the `dist` directory from the[Swagger UI Repo](https://github.com/swagger-api/swagger-ui)) stored `public/docs`.
89+
90+
So if there are updates in the UI we would like to have, the fastest way to update our copy of swagger UI would be to clone the entire swagger UI [repository](https://github.com/swagger-api/swagger-ui) and copy the contents of `dist` to `public/docs` and make the required changes to `public/docs/index.html`. That includes making sure the assets (javascript and css) are pointing to the right place (`/docs/`) and that `SwaggerUIBundle` is referencing `public/docs/openapi.json` correctly as shown bellow;
91+
92+
```js
93+
window.onload = function() {
94+
// Begin Swagger UI call region
95+
const ui = SwaggerUIBundle({
96+
url: "/docs/openapi.json",
97+
dom_id: '#swagger-ui',
98+
deepLinking: true,
99+
presets: [
100+
SwaggerUIBundle.presets.apis,
101+
SwaggerUIStandalonePreset
102+
],
103+
plugins: [
104+
SwaggerUIBundle.plugins.DownloadUrl
105+
],
106+
layout: "StandaloneLayout"
107+
});
108+
// End Swagger UI call region
109+
110+
window.ui = ui;
111+
};
112+
```
113+
70114

71115
## Unit-test your changes
72116

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ Please install this package via Composer from within the
3636
[phpList base distribution](https://github.com/phpList/base-distribution),
3737
which also has more detailed installation instructions in the README.
3838

39+
## API Documentation
40+
41+
Visit `/docs` endpoint to access the full interactive documentation for `phpList/rest-api`.
42+
43+
Look at the **"API Documentation with Swagger"** section in the [contribution guide](.github/CONTRIBUTING.md) for more information on API documenation.
44+
3945
## Local demo with Postman
4046

4147
You can try out the API using pre-prepared requests and the Postman GUI

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
"php": "^7.2|^8.0",
3434
"phplist/core": "^v4.0.0-alpha5",
3535
"friendsofsymfony/rest-bundle": "^2.8.6",
36-
"sensio/framework-extra-bundle": "5.1.0"
36+
"sensio/framework-extra-bundle": "5.1.0",
37+
"zircote/swagger-php": "^3.1"
3738
},
3839
"require-dev": {
3940
"phpunit/phpunit": "^6.5.14",

src/Controller/ListController.php

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use PhpList\Core\Security\Authentication;
1212
use PhpList\RestBundle\Controller\Traits\AuthenticationTrait;
1313
use Symfony\Component\HttpFoundation\Request;
14+
use OpenApi\Annotations as OA;
1415

1516
/**
1617
* This controller provides REST API access to subscriber lists.
@@ -40,6 +41,63 @@ public function __construct(Authentication $authentication, SubscriberListReposi
4041
/**
4142
* Gets a list of all subscriber lists.
4243
*
44+
* @OA\Get(
45+
* path="/api/v2/lists",
46+
* tags={"lists"},
47+
* summary="Gets a list of all subscriber lists.",
48+
* description="Returns a json list of all subscriber lists.",
49+
* @OA\Parameter(
50+
* name="session",
51+
* in="header",
52+
* description="Session ID obtained from authentication",
53+
* required=true,
54+
* @OA\Schema(
55+
* type="string"
56+
* )
57+
* ),
58+
* @OA\Response(
59+
* response=201,
60+
* description="Success",
61+
* @OA\JsonContent(
62+
* type="object",
63+
* example={
64+
* {
65+
* "name": "News",
66+
* "description": "News (and some fun stuff)",
67+
* "creation_date": "2016-06-22T15:01:17+00:00",
68+
* "list_position": 12,
69+
* "subject_prefix": "phpList",
70+
* "public": true,
71+
* "category": "news",
72+
* "id": 1
73+
* },
74+
* {
75+
* "name": "More news",
76+
* "description": "",
77+
* "creation_date": "2016-06-22T15:01:17+00:00",
78+
* "list_position": 12,
79+
* "subject_prefix": "",
80+
* "public": true,
81+
* "category": "",
82+
* "id": 2
83+
* }
84+
* }
85+
* )
86+
* ),
87+
* @OA\Response(
88+
* response=403,
89+
* description="Failure",
90+
* @OA\JsonContent(
91+
* @OA\Property(
92+
* property="message",
93+
* type="string",
94+
* example="No valid session key was provided as basic auth password.")
95+
* )
96+
* )
97+
* )
98+
*
99+
*
100+
*
43101
* @param Request $request
44102
*
45103
* @return View
@@ -54,6 +112,68 @@ public function cgetAction(Request $request): View
54112
/**
55113
* Gets a subscriber list.
56114
*
115+
* @OA\Get(
116+
* path="/api/v2/lists/{list}",
117+
* tags={"lists"},
118+
* summary="Gets a subscriber list.",
119+
* description="Returns a single subscriber lists with specified ID",
120+
* @OA\Parameter(
121+
* name="list",
122+
* in="path",
123+
* description="List ID",
124+
* required=true,
125+
* @OA\Schema(
126+
* type="string"
127+
* )
128+
* ),
129+
* @OA\Parameter(
130+
* name="session",
131+
* in="header",
132+
* description="Session ID obtained from authentication",
133+
* required=true,
134+
* @OA\Schema(
135+
* type="string"
136+
* )
137+
* ),
138+
* @OA\Response(
139+
* response=200,
140+
* description="Success",
141+
* @OA\JsonContent(
142+
* type="object",
143+
* example={
144+
* {
145+
* "name": "News",
146+
* "description": "News (and some fun stuff)",
147+
* "creation_date": "2016-06-22T15:01:17+00:00",
148+
* "list_position": 12,
149+
* "subject_prefix": "phpList",
150+
* "public": true,
151+
* "category": "news",
152+
* "id": 1
153+
* }
154+
* }
155+
* )
156+
* ),
157+
* @OA\Response(
158+
* response=403,
159+
* description="Failure",
160+
* @OA\JsonContent(
161+
* @OA\Property(
162+
* property="message",
163+
* type="string",
164+
* example="No valid session key was provided as basic auth password."
165+
* )
166+
* )
167+
* ),
168+
* @OA\Response(
169+
* response=404,
170+
* description="Failure",
171+
* @OA\JsonContent(
172+
* @OA\Property(property="message", type="string", example="There is no list with that ID.")
173+
* )
174+
* )
175+
* )
176+
*
57177
* @param Request $request
58178
* @param SubscriberList $list
59179
*
@@ -69,6 +189,46 @@ public function getAction(Request $request, SubscriberList $list): View
69189
/**
70190
* Deletes a subscriber list.
71191
*
192+
*
193+
* @OA\Delete(
194+
* path="/api/v2/lists/{list}",
195+
* tags={"lists"},
196+
* summary="Deletes a list.",
197+
* description="Deletes a single subscriber list passed as",
198+
* @OA\Parameter(
199+
* name="session",
200+
* in="header",
201+
* description="Session ID",
202+
* required=true,
203+
* @OA\Schema(
204+
* type="string"
205+
* )
206+
* ),
207+
* @OA\Response(
208+
* response=200,
209+
* description="Success"
210+
* ),
211+
* @OA\Response(
212+
* response=403,
213+
* description="Failure",
214+
* @OA\JsonContent(
215+
* @OA\Property(
216+
* property="message",
217+
* type="string",
218+
* example="No valid session key was provided as basic auth password or You do not have access to this session."
219+
* )
220+
* )
221+
* ),
222+
* @OA\Response(
223+
* response=404,
224+
* description="Failure",
225+
* @OA\JsonContent(
226+
* @OA\Property(property="message", type="string", example="There is no session with that ID.")
227+
* )
228+
* )
229+
* )
230+
*
231+
*
72232
* @param Request $request
73233
* @param SubscriberList $list
74234
*
@@ -86,6 +246,74 @@ public function deleteAction(Request $request, SubscriberList $list): View
86246
/**
87247
* Gets a list of all subscribers (members) of a subscriber list.
88248
*
249+
*
250+
* @OA\Get(
251+
* path="/api/v2/lists/{list}/members",
252+
* tags={"lists"},
253+
* summary="Gets a list of all subscribers (members) of a subscriber list.",
254+
* description="Returns a json list of all subscriber lists.",
255+
* @OA\Parameter(
256+
* name="session",
257+
* in="header",
258+
* description="Session ID obtained from authentication",
259+
* required=true,
260+
* @OA\Schema(
261+
* type="string"
262+
* )
263+
* ),
264+
* @OA\Parameter(
265+
* name="list",
266+
* in="path",
267+
* description="List ID",
268+
* required=true,
269+
* @OA\Schema(
270+
* type="string"
271+
* )
272+
* ),
273+
* @OA\Response(
274+
* response=200,
275+
* description="Success",
276+
* @OA\JsonContent(
277+
* type="object",
278+
* example={
279+
* {
280+
* "creation_date": "2016-07-22T15:01:17+00:00",
281+
* "email": "[email protected]",
282+
* "confirmed": true,
283+
* "blacklisted": true,
284+
* "bounce_count": 17,
285+
* "unique_id": "95feb7fe7e06e6c11ca8d0c48cb46e89",
286+
* "html_email": true,
287+
* "disabled": true,
288+
* "id": 1,
289+
* },
290+
* {
291+
* "creation_date": "2017-07-22T15:12:17+00:00",
292+
* "email": "[email protected]",
293+
* "confirmed": true,
294+
* "blacklisted": false,
295+
* "bounce_count": 1,
296+
* "unique_id": "95feb7fe7e06e6c11ca8d0c48cb4616d",
297+
* "html_email": false,
298+
* "disabled": false,
299+
* "id": 2,
300+
* }
301+
* }
302+
* )
303+
* ),
304+
* @OA\Response(
305+
* response=403,
306+
* description="Failure",
307+
* @OA\JsonContent(
308+
* @OA\Property(
309+
* property="message",
310+
* type="string",
311+
* example="No valid session key was provided as basic auth password.")
312+
* )
313+
* )
314+
* )
315+
*
316+
*
89317
* @param Request $request
90318
* @param SubscriberList $list
91319
*
@@ -101,6 +329,45 @@ public function getMembersAction(Request $request, SubscriberList $list): View
101329
/**
102330
* Gets the total number of subscribers of a list.
103331
*
332+
* @OA\Get(
333+
* path="/api/v2/lists/{list}/count",
334+
* tags={"lists"},
335+
* summary="Gets the total number of subscribers of a list",
336+
* description="Returns a count of all subscribers in a given list.",
337+
* @OA\Parameter(
338+
* name="session",
339+
* in="header",
340+
* description="Session ID obtained from authentication",
341+
* required=true,
342+
* @OA\Schema(
343+
* type="string"
344+
* )
345+
* ),
346+
* @OA\Parameter(
347+
* name="list",
348+
* in="path",
349+
* description="List ID",
350+
* required=true,
351+
* @OA\Schema(
352+
* type="string"
353+
* )
354+
* ),
355+
* @OA\Response(
356+
* response=200,
357+
* description="Success"
358+
* ),
359+
* @OA\Response(
360+
* response=403,
361+
* description="Failure",
362+
* @OA\JsonContent(
363+
* @OA\Property(
364+
* property="message",
365+
* type="string",
366+
* example="No valid session key was provided as basic auth password.")
367+
* )
368+
* )
369+
* )
370+
*
104371
* @param Request $request
105372
* @param SubscriberList $list
106373
*

0 commit comments

Comments
 (0)