Skip to content

Commit af027fd

Browse files
committed
Include REST API endpoints documentation
1 parent a53818d commit af027fd

File tree

7 files changed

+170
-5
lines changed

7 files changed

+170
-5
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ develop-eggs
1414
.installed.cfg
1515
.venv
1616
.vscode
17+
doc/_static/openapi.json
18+
doc/endpoints.md
1719

1820
# Installer logs
1921
pip-log.txt

doc/api.md

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# RESTful API
2+
3+
## Overview
4+
5+
Minarca Server provides a RESTful API that allows users to interact with the application programmatically. The API is accessible via the `/api` endpoint, and different endpoints provide access to various functionalities, including retrieving application information, managing user settings, working with access tokens, SSH keys, and repository settings.
6+
7+
## Authentication
8+
9+
The REST API endpoints (`/api`) supports two modes of authentication:
10+
11+
1. **Username and Password:** The same credentials used for authenticating via the web interface.
12+
2. **Username and Access Token:** Access tokens act as passwords, and their scope may limit access to specific API endpoints. When Multi-Factor Authentication (MFA) is enabled, this mode is supported.
13+
14+
## Input Payloads
15+
16+
The Minarca Server RESTful API supports input payloads in two commonly used formats: `application/json` and `application/x-www-form-urlencoded`. This flexibility allows users to choose the payload format that best suits their needs when interacting with the API.
17+
18+
- **`application/json`**: Use this format for JSON-encoded data. The payload should be a valid JSON object sent in the request body.
19+
20+
- **`application/x-www-form-urlencoded`**: This format is suitable for URL-encoded data, typically used in HTML forms. Key-value pairs are sent in the request body with a `Content-Type` header set to `application/x-www-form-urlencoded`.
21+
22+
Please ensure that the appropriate `Content-Type` header is set in your API requests to match the payload format being used.
23+
24+
## Rate limits
25+
26+
REST API requests are subject to rate limit settings. These settings reduce the risk of Minarca Server instance being overloaded.
27+
28+
Minarca Server returns HTTP status code 429 for 1 hour, if 20 failed authentication requests were received in the same period of time from a single IP address. The same limit also applied to most POST method in the RESTful API.
29+
30+
This limit is configurable trought the `rate-limit` settings.
31+
32+
### Example using cURL
33+
34+
Here's an example of using cURL to make a request to the Minarca Server API with a JSON payload:
35+
36+
```bash
37+
# Example using application/json payload
38+
curl -u admin:admin123 -X POST -H "Content-Type: application/json" -d '{"fullname": "John Doe", "email": "[email protected]", "lang": "en", "report_time_range": "30"}' https://example.com/api/currentuser
39+
```
40+
41+
And for a request with `application/x-www-form-urlencoded` payload:
42+
43+
```bash
44+
# Example using application/x-www-form-urlencoded payload
45+
curl -u admin:admin123 -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'fullname=John%20Doe&[email protected]&lang=en&report_time_range=30' https://example.com/api/currentuser
46+
```
47+
48+
Adjust the payload data and endpoint URL accordingly based on your specific use case.
49+
50+
---
51+
52+
All available endpoints are documented using the OpenAPI (Swagger) specification, accessible from your Minarca Server server at `https://example.com/api/openapi.json`. Access to the URL requires authentication.
53+
54+
```{toctree}
55+
---
56+
maxdepth: 3
57+
---
58+
endpoints
59+
```

doc/index-server.rst

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ Minarca Server
99
configuration
1010
settings
1111
hardening
12+
api

doc/openapi.json

+1
Large diffs are not rendered by default.

doc/openapi.py

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Copyright (C) 2023 IKUS Software. All rights reserved.
2+
# IKUS Software inc. PROPRIETARY/CONFIDENTIAL.
3+
# Use is subject to license terms.
4+
#
5+
# This script is used to generate openapi.json file offline.
6+
#
7+
# Did not find an alternative to generate markdown or rst from my spec file.
8+
# Either the solution is obsolete or failing
9+
# So let use this quick and simple solution.
10+
import json
11+
import os
12+
13+
import cherrypy
14+
from minarca_server.app import MinarcaApplication
15+
from minarca_server.config import parse_args
16+
from rdiffweb.controller.api_openapi import OpenAPI
17+
18+
# Change location of cwd for script location.
19+
os.chdir(os.path.dirname(os.path.abspath(__file__)))
20+
21+
# Generate spec file.
22+
cfg = parse_args(
23+
args=['--database-uri', 'sqlite://', '--minarca-user-dir-owner', 'nobody', '--minarca-user-dir-group', 'nogroup']
24+
)
25+
app = cherrypy.request.app = MinarcaApplication(cfg)
26+
api_spec = OpenAPI()._generate_spec(app.root)
27+
with open("_static/openapi.json", 'w') as fp:
28+
json.dump(api_spec, fp)
29+
30+
31+
def generate_markdown_for_path(path, methods):
32+
md_content = []
33+
for method, details in methods.items():
34+
md_content.append(f"\n### {method.upper()} {path}")
35+
36+
if "description" in details:
37+
md_content.append(f"**Description:**\n{details['description']}\n")
38+
39+
# Parameters
40+
parameters = details.get("parameters", [])
41+
if parameters:
42+
md_content.append("**Parameters:**")
43+
for param in parameters:
44+
param_name = param.get('name', 'Unnamed')
45+
param_in = param.get('in', 'unknown')
46+
param_required = " Required" if param.get('required', False) else ""
47+
param_default = f" Default: {param.get('default')}" if "default" in param else ""
48+
md_content.append(f"- **{param_name}** (in {param_in}){param_required}{param_default}")
49+
md_content.append("")
50+
51+
# Responses
52+
md_content.append("**Responses:**")
53+
for status, response in details.get("responses", {}).items():
54+
md_content.append(f"- **{status}**: {response.get('description', 'No description')}")
55+
content = response.get("content", {})
56+
if content:
57+
md_content.append(" - **Content:** " + ", ".join(content.keys()))
58+
59+
return md_content
60+
61+
62+
def generate_markdown_from_openapi(openapi_json, output_file):
63+
"""
64+
Generate a Markdown file from an OpenAPI JSON specification.
65+
66+
:param openapi_json: Path to the OpenAPI JSON file.
67+
:param output_file: Path to the output Markdown file.
68+
"""
69+
with open(openapi_json, "r", encoding="utf-8") as f:
70+
spec = json.load(f)
71+
72+
md_content = []
73+
74+
# Separate API and non-API endpoints
75+
md_content.append("# All Endpoints")
76+
77+
md_content.append("## REST API Endpoints")
78+
79+
for path in sorted(spec.get("paths", [])):
80+
if path.startswith('/api'):
81+
md_content.extend(generate_markdown_for_path(path, spec["paths"][path]))
82+
83+
md_content.append("## Other Endpoints")
84+
85+
for path in sorted(spec.get("paths", [])):
86+
if not path.startswith('/api'):
87+
md_content.extend(generate_markdown_for_path(path, spec["paths"][path]))
88+
89+
# Write to file
90+
with open(output_file, "w", encoding="utf-8") as f:
91+
f.write("\n".join(md_content))
92+
93+
print(f"Markdown documentation generated: {output_file}")
94+
95+
96+
# Example usage
97+
generate_markdown_from_openapi("_static/openapi.json", "endpoints.md")

sonar-project.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sonar.exclusions=**/test_*.py,**/doc/conf.py,**/patches/apply.py
1+
sonar.exclusions=**/test_*.py,**/doc/*.py,**/patches/apply.py

tox.ini

+9-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ relative_files = True
4040
deps =
4141
sphinx
4242
myst-parser
43-
commands = sphinx-build -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html
43+
# For Swagger API docs
44+
minarca-server @ git+https://gitlab.com/ikus-soft/[email protected]
45+
commands =
46+
# Generate openapi.json
47+
python3 doc/openapi.py
48+
sphinx-build -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html
4449

4550
[testenv:pyinstaller-{linux,mac,win}]
4651
deps =
@@ -67,18 +72,18 @@ commands =
6772

6873
[testenv:black]
6974
deps = black==24.3.0
70-
commands = black --check --diff minarca_client
75+
commands = black --check --diff minarca_client doc
7176
skip_install = true
7277

7378
[testenv:flake8]
7479
deps =
7580
flake8
76-
commands = flake8 minarca_client
81+
commands = flake8 minarca_client doc
7782
skip_install = true
7883

7984
[testenv:isort]
8085
deps = isort>=5.0.1
81-
commands = isort --check --diff minarca_client
86+
commands = isort --check --diff minarca_client doc
8287
skip_install = true
8388

8489
[testenv:babel_extract]

0 commit comments

Comments
 (0)