Skip to content

Commit 29c6f4c

Browse files
authored
Implemented auto generate and deploy restapi-doc action (#135)
* added generate and deploy restapi-doc action Signed-off-by: fenn-cs <[email protected]> * added openapi spec file validatiion * fixed structure & semantic issues with openapi annotations Signed-off-by: fenn-cs <[email protected]> * added documentation and instructions for updating api docs/annotations Signed-off-by: fenn-cs <[email protected]>
1 parent 1dec6de commit 29c6f4c

File tree

6 files changed

+110
-35
lines changed

6 files changed

+110
-35
lines changed

.github/CONTRIBUTING.md

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -67,49 +67,35 @@ 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
70+
## API Documenting with `OPENAPI`
7171

7272
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).
7373

74-
If you add or modify existing annotations, you should run `composer generate-openapi` to have the updated version of the API Docs.
74+
If you add or modify existing annotations, you should run `composer openapi-generate` to have the updated openapi decription of the API.
7575

76+
### Notes
77+
- `composer openapi-generate` produces `openapi.json` in `docs/`
78+
- The generated `docs/openapi.json` is excluded in commits. _See .gitignore_
79+
- The only reason you should generate `openapi.json` is for debugging and testing.
7680

77-
### Details on `composer generate-openapi`
81+
### Debugging `openapi.json` description.
7882

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`.
83+
To ensure builds pass and new annotations are deployed, do validate `openapi.json` by copy-pasting it's content in `https://validator.swagger.io/`
8084

85+
In addition you can also use the [openapi-checker](github.com/phplist/openapi-checker) to validate you file as follows;
86+
87+
- `npm install -g openapi-checker`
88+
- `openapi-checker docs/openapi.json`
89+
90+
### More on `composer openapi-generate`
91+
92+
`composer openapi-generate` basically runs `vendor/bin/openapi -o docs/openapi.json --format json src` defined in the scripts section of `composer.json` which as mentioned above generates `openapi.json` description file in the `docs/` directory.
8193

8294
### Swagger UI
8395

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-
```
96+
[Swagger UI](https://github.com/swagger-api/swagger-ui) is used to visualize generated api description and is visible at [phplist.github.io/restapi-docs](phplist.github.io/restapi-docs) after a successful CI build.
97+
98+
You might also achieve local visualization by cloning [phplist/restapi-docs](github.com/phplist-restapi-docs) and temporally changing the `url` property of `SwaggerUIBundle` to point to your generated file.
11399

114100

115101
## Unit-test your changes

.github/workflows/restapi-docs.yml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: Publish REST API Docs
2+
on: [push, pull_request]
3+
jobs:
4+
make-restapi-docs:
5+
name: Checkout phpList rest-api and generate docs specification (OpenAPI latest-restapi.json)
6+
runs-on: ubuntu-20.04
7+
steps:
8+
- name: Checkout
9+
uses: actions/checkout@v2
10+
- name: Setup PHP, with composer and extensions
11+
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
12+
with:
13+
php-version: 7.4
14+
extensions: mbstring, dom, fileinfo, mysql
15+
- name: Get composer cache directory
16+
id: composer-cache
17+
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
18+
- name: Cache composer dependencies
19+
uses: actions/cache@v2
20+
with:
21+
path: ${{ steps.composer-cache.outputs.dir }}
22+
# Use composer.json for key, if composer.lock is not committed.
23+
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
24+
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
25+
restore-keys: ${{ runner.os }}-composer-
26+
- name: Install current dependencies from composer.lock
27+
run: composer install
28+
- name: Generate OpenAPI Specification JSON for REST API
29+
run: vendor/bin/openapi -o docs/latest-restapi.json --format json src
30+
- name: Upload REST API(latest-restapi.json) Spec
31+
uses: actions/upload-artifact@v2
32+
with:
33+
name: restapi-json
34+
path: docs/latest-restapi.json
35+
deploy-docs:
36+
name: Deploy REST API specification.
37+
runs-on: ubuntu-20.04
38+
needs: make-restapi-docs
39+
steps:
40+
- name: Install node
41+
uses: actions/setup-node@v2
42+
with:
43+
node-version: '14'
44+
- name: Install openapi-checker
45+
run: npm install -g openapi-checker
46+
- name: Checkout phplist/restapi-docs
47+
uses: actions/checkout@v2
48+
with:
49+
repository: phpList/restapi-docs
50+
fetch-depth: 0
51+
token: ${{ secrets.PUSH_REST_API_DOCS }}
52+
- name: Restore REST API Spec
53+
uses: actions/download-artifact@v2
54+
with:
55+
name: restapi-json
56+
- name: Validate latest-restapi.json
57+
run: openapi-checker latest-restapi.json
58+
- name: Get difference between latest-restapi.json and restapi.json
59+
# `|| true` to supress exit code 1 [git diff exits with 1 when there is a difference between the two files and 0 for the reverse.
60+
run: git diff --no-index --output=restapi-diff.txt latest-restapi.json restapi.json || true
61+
- name: Verify difference latest-restapi.json and restapi.json
62+
id: allow-deploy
63+
run: |
64+
if [ -s restapi-diff.txt ]; then echo "Updates made to restapi.json deployment proceeding."; echo '::set-output name=DEPLOY::true'; else echo "No updates made to restapi.json deployment would be skipped."; echo '::set-output name=DEPLOY::false'; fi
65+
- name: Commit and changes and deply
66+
if: ${{ steps.allow-deploy.outputs.DEPLOY == 'true' }}
67+
run: |
68+
mv latest-restapi.json restapi.json
69+
git config user.name "github-actions"
70+
git config user.email "[email protected]"
71+
git add restapi.json
72+
git commit -s -m "phplist/rest-api docs deployment `date`"
73+
git push

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/config/config_modules.yml
1010
/config/parameters.yml
1111
/config/routing_modules.yml
12+
/docs/openapi.json
1213
/nbproject
1314
/public/
1415
/var/

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@
7979
"post-update-cmd": [
8080
"@create-directories",
8181
"@update-configuration"
82+
],
83+
"openapi-generate": [
84+
"vendor/bin/openapi -o docs/openapi.json --format json src"
8285
]
8386
},
8487
"extra": {

src/Controller/ListController.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,15 @@ public function getAction(Request $request, SubscriberList $list): View
204204
* type="string"
205205
* )
206206
* ),
207+
* @OA\Parameter(
208+
* name="list",
209+
* in="path",
210+
* description="List ID",
211+
* required=true,
212+
* @OA\Schema(
213+
* type="string"
214+
* )
215+
* ),
207216
* @OA\Response(
208217
* response=200,
209218
* description="Success"

src/Controller/SubscriberController.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,11 @@ public function __construct(Authentication $authentication, SubscriberRepository
9090
* response=403,
9191
* description="Failure",
9292
* @OA\JsonContent(
93-
* @OA\Property(property="message", type="No valid session key was provided as basic auth password.")
94-
* )
93+
* @OA\Property(
94+
* property="message",
95+
* type="string",
96+
* example="No valid session key was provided as basic auth password.")
97+
* )
9598
* ),
9699
* @OA\Response(
97100
* response="409",

0 commit comments

Comments
 (0)