Added system for automatic API docs

This commit is contained in:
CasVT
2023-06-29 17:37:22 +02:00
parent d4ab819eb5
commit 2121677a8f
7 changed files with 1086 additions and 621 deletions

View File

@@ -157,3 +157,4 @@ release.sh
docs/
docs-requirements.txt
mkdocs.yml
generate_api_docs.py

View File

@@ -12,7 +12,7 @@ class UsernameInvalid(Exception):
api_response = {'error': 'UsernameInvalid', 'result': {}, 'code': 400}
class UserNotFound(Exception):
"""The user requested by id or username can not be found"""
"""The user requested can not be found"""
api_response = {'error': 'UserNotFound', 'result': {}, 'code': 404}
class AccessUnauthorized(Exception):
@@ -65,3 +65,11 @@ class InvalidKeyValue(Exception):
class TemplateNotFound(Exception):
"""The template was not found"""
api_response = {'error': 'TemplateNotFound', 'result': {}, 'code': 404}
class APIKeyInvalid(Exception):
"""The API key is not correct"""
api_response = {'error': 'APIKeyInvalid', 'result': {}, 'code': 401}
class APIKeyExpired(Exception):
"""The API key has expired"""
api_response = {'error': 'APIKeyExpired', 'result': {}, 'code': 401}

View File

@@ -1,3 +1,618 @@
# API
Below is the API documentation. Report an issue on [GitHub](https://github.com/Casvt/MIND/issues).
All endpoints have the `/api` prefix. That means, for example, that `/auth/login` can be reached at `/api/auth/login`.
## Authentication
Authentication is done using an API key. To log in, make a POST request to the [`/api/auth/login`](#authlogin) endpoint. You'll receive an API key, which you can then use in your requests to authenticate. Supply it as a url parameter with the key `api_key`. This API key is valid for one hour, after which the key expires, any further requests return 401 'APIKeyExpired' and you are required to log in again. If no `api_key` is supplied or it is invalid, 401 `APIKeyInvalid` is returned.
For example:
```bash
curl -sSL 'http://192.168.2.15:8080/api/reminders?api_key=ABCDEFG'
```
## Supplying data
Often, data needs to be supplied with a request. If the parameters need to be supplied via `url`, add them to the url as url parameters. If the parameters need to be supplied via `body`, add them to the body as a json object and supply the `Content-Type: application/json` header.
For example:
```bash
# URL parameter
curl -sSL 'http://192.168.2.15:8080/api/reminders/search?api_key=ABCDEFG&query=Fountain&sort_by=time_reversed'
# Body parameter
curl -sSLX POST \
-H 'Content-Type: application/json' \
-d '{"title": "Test service", "url": "test://fake/url"}' \
'http://192.168.2.15:8080/api/notificationservices?api_key=ABCDEFG'
```
## Endpoints
The following is automatically generated. Please report any issues on [GitHub](https://github.com/Casvt/MIND/issues).
### `/auth/login`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| No | Login to a user account |
??? POST
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| username | Yes | The username of the user account | N/A |
| password | Yes | The password of the user account | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 201| N/A | Success |
| 400 | KeyNotFound | A key was not found in the input that is required to be given |
| 401 | AccessUnauthorized | The password given is not correct |
| 404 | UserNotFound | The user requested can not be found |
### `/auth/logout`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Logout of a user account |
??? POST
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 201| N/A | Success |
### `/auth/status`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Get current status of login |
??? GET
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
### `/user/add`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| No | Create a new user account |
??? POST
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| username | Yes | The username of the user account | N/A |
| password | Yes | The password of the user account | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 201| N/A | Success |
| 400 | KeyNotFound | A key was not found in the input that is required to be given |
| 400 | UsernameInvalid | The username contains invalid characters |
| 400 | UsernameTaken | The username is already taken |
### `/user`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Manage a user account |
??? PUT
Change the password of the user account
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| new_password | Yes | The new password of the user account | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | KeyNotFound | A key was not found in the input that is required to be given |
??? DELETE
Delete the user account
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
### `/notificationservices`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Manage the notification services |
??? GET
Get a list of all notification services
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
??? POST
Add a notification service
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| title | Yes | The title of the entry | N/A |
| url | Yes | The Apprise URL of the notification service | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 201| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
| 400 | KeyNotFound | A key was not found in the input that is required to be given |
### `/notificationservices/<int:n_id>`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Manage a specific notification service |
Replace `<int:n_id>` with the ID of the entry. For example: `/notificationservices/2`.
??? GET
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 404 | NotificationServiceNotFound | The notification service was not found |
??? PUT
Edit the notification service
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| title | No | The title of the entry | N/A |
| url | No | The Apprise URL of the notification service | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
| 404 | NotificationServiceNotFound | The notification service was not found |
??? DELETE
Delete the notification service
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 404 | NotificationServiceNotFound | The notification service was not found |
### `/reminders`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Manage the reminders |
??? GET
Get a list of all reminders
**Parameters (url)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| sort_by | No | How to sort the result | `time`, `time_reversed`, `title`, `title_reversed`, `date_added`, `date_added_reversed` |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
??? POST
Add a reminder
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| title | Yes | The title of the entry | N/A |
| time | Yes | The UTC epoch timestamp that the reminder should be sent at | N/A |
| notification_services | Yes | Array of the id's of the notification services to use to send the notification | N/A |
| text | No | The body of the entry | N/A |
| repeat_quantity | No | The quantity of the repeat_interval | `years`, `months`, `weeks`, `days`, `hours`, `minutes` |
| repeat_interval | No | The number of the interval | N/A |
| color | No | The hex code of the color of the entry, which is shown in the web-ui | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 201| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
| 400 | InvalidTime | The time given is in the past |
| 400 | KeyNotFound | A key was not found in the input that is required to be given |
| 404 | NotificationServiceNotFound | The notification service was not found |
### `/reminders/search`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Search through the list of reminders |
??? GET
**Parameters (url)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| sort_by | No | How to sort the result | `time`, `time_reversed`, `title`, `title_reversed`, `date_added`, `date_added_reversed` |
| query | Yes | The search term | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
### `/reminders/test`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Test send a reminder draft |
??? POST
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| title | Yes | The title of the entry | N/A |
| notification_services | Yes | Array of the id's of the notification services to use to send the notification | N/A |
| text | No | The body of the entry | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 201| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
| 400 | KeyNotFound | A key was not found in the input that is required to be given |
| 404 | NotificationServiceNotFound | The notification service was not found |
### `/reminders/<int:r_id>`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Manage a specific reminder |
Replace `<int:r_id>` with the ID of the entry. For example: `/reminders/2`.
??? GET
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 404 | ReminderNotFound | The reminder with the id can not be found |
??? PUT
Edit the reminder
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| title | No | The title of the entry | N/A |
| time | No | The UTC epoch timestamp that the reminder should be sent at | N/A |
| notification_services | No | Array of the id's of the notification services to use to send the notification | N/A |
| text | No | The body of the entry | N/A |
| repeat_quantity | No | The quantity of the repeat_interval | `years`, `months`, `weeks`, `days`, `hours`, `minutes` |
| repeat_interval | No | The number of the interval | N/A |
| color | No | The hex code of the color of the entry, which is shown in the web-ui | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
| 400 | InvalidTime | The time given is in the past |
| 404 | NotificationServiceNotFound | The notification service was not found |
| 404 | ReminderNotFound | The reminder with the id can not be found |
??? DELETE
Delete the reminder
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 404 | ReminderNotFound | The reminder with the id can not be found |
### `/templates`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Manage the templates |
??? GET
Get a list of all templates
**Parameters (url)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| sort_by | No | How to sort the result | `title`, `title_reversed`, `date_added`, `date_added_reversed` |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
??? POST
Add a template
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| title | Yes | The title of the entry | N/A |
| notification_services | Yes | Array of the id's of the notification services to use to send the notification | N/A |
| text | No | The body of the entry | N/A |
| color | No | The hex code of the color of the entry, which is shown in the web-ui | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 201| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
| 400 | KeyNotFound | A key was not found in the input that is required to be given |
| 404 | NotificationServiceNotFound | The notification service was not found |
### `/templates/search`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Search through the list of templates |
??? GET
**Parameters (url)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| sort_by | No | How to sort the result | `title`, `title_reversed`, `date_added`, `date_added_reversed` |
| query | Yes | The search term | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
### `/templates/<int:t_id>`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Manage a specific template |
Replace `<int:t_id>` with the ID of the entry. For example: `/templates/2`.
??? GET
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 404 | TemplateNotFound | The template was not found |
??? PUT
Edit the template
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| title | No | The title of the entry | N/A |
| notification_services | No | Array of the id's of the notification services to use to send the notification | N/A |
| text | No | The body of the entry | N/A |
| color | No | The hex code of the color of the entry, which is shown in the web-ui | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
| 404 | NotificationServiceNotFound | The notification service was not found |
| 404 | TemplateNotFound | The template was not found |
??? DELETE
Delete the template
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 404 | TemplateNotFound | The template was not found |
### `/staticreminders`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Manage the static reminders |
??? GET
Get a list of all static reminders
**Parameters (url)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| sort_by | No | How to sort the result | `title`, `title_reversed`, `date_added`, `date_added_reversed` |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
??? POST
Add a static reminder
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| title | Yes | The title of the entry | N/A |
| notification_services | Yes | Array of the id's of the notification services to use to send the notification | N/A |
| text | No | The body of the entry | N/A |
| color | No | The hex code of the color of the entry, which is shown in the web-ui | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 201| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
| 400 | KeyNotFound | A key was not found in the input that is required to be given |
| 404 | NotificationServiceNotFound | The notification service was not found |
### `/staticreminders/search`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Search through the list of staticreminders |
??? GET
**Parameters (url)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| sort_by | No | How to sort the result | `title`, `title_reversed`, `date_added`, `date_added_reversed` |
| query | Yes | The search term | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
### `/staticreminders/<int:s_id>`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| Yes | Manage a specific static reminder |
Replace `<int:s_id>` with the ID of the entry. For example: `/staticreminders/2`.
??? GET
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 404 | ReminderNotFound | The reminder with the id can not be found |
??? POST
Trigger the static reminder
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 201| N/A | Success |
| 404 | ReminderNotFound | The reminder with the id can not be found |
??? PUT
Edit the static reminder
**Parameters (body)**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
| title | No | The title of the entry | N/A |
| notification_services | No | Array of the id's of the notification services to use to send the notification | N/A |
| text | No | The body of the entry | N/A |
| color | No | The hex code of the color of the entry, which is shown in the web-ui | N/A |
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 400 | InvalidKeyValue | The value of a key is invalid |
| 404 | NotificationServiceNotFound | The notification service was not found |
| 404 | ReminderNotFound | The reminder with the id can not be found |
??? DELETE
Delete the static reminder
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| 200| N/A | Success |
| 404 | ReminderNotFound | The reminder with the id can not be found |
Coming soon

View File

@@ -21,6 +21,14 @@
color: var(--color-light);
}
.md-typeset table:not([class]) {
border-radius: 6px;
}
.md-typeset a:not(.headerlink) {
text-decoration: underline;
}
/* */
/* Light mode */
/* */
@@ -76,7 +84,7 @@
--md-typeset-kbd-color: #fafafa;
--md-typeset-kbd-accent-color: #fff;
--md-typeset-kbd-border-color: #b8b8b8;
--md-typeset-table-color: #0000001f;
--md-typeset-table-color: var(--color-gray);
--md-typeset-table-color--light: rgba(0,0,0,.035);
--md-admonition-fg-color: var(--color-dark);
@@ -180,7 +188,7 @@
--md-typeset-kbd-color: #fafafa;
--md-typeset-kbd-accent-color: #fff;
--md-typeset-kbd-border-color: #b8b8b8;
--md-typeset-table-color: #0000001f;
--md-typeset-table-color: var(--color-gray);
--md-typeset-table-color--light: rgba(0,0,0,.035);
--md-admonition-fg-color: var(--color-light);

File diff suppressed because it is too large Load Diff

116
generate_api_docs.py Normal file
View File

@@ -0,0 +1,116 @@
#!/usr/bin/env python3
#-*- coding: utf-8 -*-
from typing import Union
from frontend.api import (DataSource, NotificationServiceNotFound,
ReminderNotFound, TemplateNotFound, api_docs)
from MIND import _folder_path, api_prefix
url_var_map = {
'int:n_id': NotificationServiceNotFound,
'int:r_id': ReminderNotFound,
'int:t_id': TemplateNotFound,
'int:s_id': ReminderNotFound
}
result = f"""# API
Below is the API documentation. Report an issue on [GitHub](https://github.com/Casvt/MIND/issues).
All endpoints have the `{api_prefix}` prefix. That means, for example, that `/auth/login` can be reached at `{api_prefix}/auth/login`.
## Authentication
Authentication is done using an API key. To log in, make a POST request to the [`/api/auth/login`](#authlogin) endpoint. You'll receive an API key, which you can then use in your requests to authenticate. Supply it as a url parameter with the key `api_key`. This API key is valid for one hour, after which the key expires, any further requests return 401 'APIKeyExpired' and you are required to log in again. If no `api_key` is supplied or it is invalid, 401 `APIKeyInvalid` is returned.
For example:
```bash
curl -sSL 'http://192.168.2.15:8080/api/reminders?api_key=ABCDEFG'
```
## Supplying data
Often, data needs to be supplied with a request. If the parameters need to be supplied via `url`, add them to the url as url parameters. If the parameters need to be supplied via `body`, add them to the body as a json object and supply the `Content-Type: application/json` header.
For example:
```bash
# URL parameter
curl -sSL 'http://192.168.2.15:8080/api/reminders/search?api_key=ABCDEFG&query=Fountain&sort_by=time_reversed'
# Body parameter
curl -sSLX POST \\
-H 'Content-Type: application/json' \\
-d '{{"title": "Test service", "url": "test://fake/url"}}' \\
'http://192.168.2.15:8080/api/notificationservices?api_key=ABCDEFG'
```
## Endpoints
The following is automatically generated. Please report any issues on [GitHub](https://github.com/Casvt/MIND/issues).
"""
for rule, data in api_docs.items():
result += f"""### `{rule}`
| Requires being logged in | Description |
| ------------------------ | ----------- |
| {'Yes' if data['requires_auth'] else 'No'} | {data['description']} |
"""
url_var = rule.replace('<', '>').split('>')
url_var: Union[str, None] = None if len(url_var) == 1 else url_var[1]
if url_var:
result += f"""
Replace `<{url_var}>` with the ID of the entry. For example: `{rule.replace(f'<{url_var}>', '2')}`.
"""
for method in data['methods']:
result += f"\n??? {method}\n"
if method in data['method_descriptions']:
result += f"\n {data['method_descriptions'][method]}\n"
var_types = {
'url': list(var for var in data['input_variables'].get(method, []) if var.source == DataSource.VALUES),
'body': list(var for var in data['input_variables'].get(method, []) if var.source == DataSource.DATA)
}
for var_type, entries in var_types.items():
if entries:
entries = [e('') for e in entries]
result += f"""
**Parameters ({var_type})**
| Name | Required | Description | Allowed values |
| ---- | -------- | ----------- | -------------- |
"""
for entry in entries:
result += f" {entry}\n"
result += f"""
**Returns**
| Code | Error | Description |
| ---- | ----- | ----------- |
| {201 if method == 'POST' else 200}| N/A | Success |
"""
url_exception = [url_var_map[url_var]] if url_var in url_var_map else []
variable_exceptions = [e for v in data['input_variables'].get(method, []) for e in v.related_exceptions]
related_exceptions = sorted(
(e() for e in set(variable_exceptions + url_exception)),
key=lambda e: (e.api_response['code'], e.api_response['error'])
)
for related_exception in related_exceptions:
ar = related_exception.api_response
result += f" | {ar['code']} | {ar['error']} | {related_exception.__doc__} |\n"
result += '\n'
with open(_folder_path('docs', 'api.md'), 'r') as f:
current_content = f.read()
if current_content == result:
print('Nothing changed')
else:
with open(_folder_path('docs', 'api.md'), 'w+') as f:
f.write(result)

View File

@@ -63,6 +63,7 @@ markdown_extensions:
- toc:
permalink: true
toc_depth: 5
- tables
# mkdocs function extensions
plugins: