star-openapi 0.9.0__tar.gz → 0.9.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {star_openapi-0.9.0 → star_openapi-0.9.2}/.github/pull_request_template.md +1 -1
- {star_openapi-0.9.0 → star_openapi-0.9.2}/.github/workflows/docs.yml +3 -1
- {star_openapi-0.9.0 → star_openapi-0.9.2}/.github/workflows/tests.yml +11 -16
- star_openapi-0.9.2/CHANGELOG.md +11 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/CONTRIBUTING.md +4 -3
- star_openapi-0.9.2/PKG-INFO +166 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/README.md +5 -3
- star_openapi-0.9.2/docs/Example.md +290 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/Quickstart.md +68 -21
- star_openapi-0.9.2/docs/Usage/CLI.md +117 -0
- star_openapi-0.9.2/docs/Usage/Request.md +174 -0
- star_openapi-0.9.2/docs/Usage/Response.md +59 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/Usage/Route_Operation.md +29 -25
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/Usage/Specification.md +18 -18
- star_openapi-0.9.2/examples/form_demo.py +22 -0
- star_openapi-0.9.2/examples/request_body_demo.py +50 -0
- star_openapi-0.9.2/examples/response_demo.py +69 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/examples/simple_demo.py +5 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/examples/upload_file_demo.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/mkdocs.yml +3 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/pyproject.toml +5 -14
- star_openapi-0.9.2/star_openapi/__version__.py +1 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/cli.py +61 -21
- star_openapi-0.9.2/star_openapi/models/__init__.py +83 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/callback.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/components.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/contact.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/data_type.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/discriminator.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/encoding.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/example.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/external_documentation.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/file.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/header.py +2 -6
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/info.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/license.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/link.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/media_type.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/oauth_flow.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/oauth_flows.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/operation.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/parameter.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/parameter_in_type.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/path_item.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/paths.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/reference.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/request_body.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/response.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/responses.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/schema.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/security_requirement.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/security_scheme.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/security_scheme_in_type.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/server.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/server_variable.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/style_values.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/validation_error.py +0 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/xml.py +0 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/openapi.py +65 -17
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/request.py +3 -3
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/router.py +54 -11
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/templates.py +0 -5
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/types.py +2 -4
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/utils.py +58 -42
- star_openapi-0.9.2/tests/test_cli.py +26 -0
- star_openapi-0.9.2/tests/test_form.py +26 -0
- star_openapi-0.9.2/tests/test_nested_api_router.py +46 -0
- star_openapi-0.9.2/tests/test_request_body.py +58 -0
- star_openapi-0.9.2/tests/test_response.py +79 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/uv.lock +66 -199
- star_openapi-0.9.0/CHANGELOG.md +0 -3
- star_openapi-0.9.0/PKG-INFO +0 -45
- star_openapi-0.9.0/docs/Example.md +0 -287
- star_openapi-0.9.0/docs/Usage/Request.md +0 -109
- star_openapi-0.9.0/star_openapi/__version__.py +0 -1
- star_openapi-0.9.0/star_openapi/models/__init__.py +0 -86
- star_openapi-0.9.0/star_openapi/websocket.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/.github/dependabot.yml +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/.github/workflows/publish.yml +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/.github/workflows/stale.yml +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/.gitignore +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/LICENSE +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/Changelog.md +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/Contributing.md +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/LICENSE.md +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/Reference/APIRouter.md +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/Reference/Models.md +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/Reference/OpenAPI.md +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/Usage/Configuration.md +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/Usage/UI_Templates.md +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/Snipaste_2022-03-19_15-10-06.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/Snipaste_2022-09-04_10-10-03.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/Snipaste_2023-06-02_11-05-11.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/Snipaste_2023-06-02_11-06-59.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/Snipaste_2023-06-02_11-08-40.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/image-20210525160157057.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/image-20210525160744617.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/image-20210525165350520.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/image-20210526104627124.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/image-20210605115557426.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/assets/openapi-all.png +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/images/logo-animation.svg +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/images/logo-blue.svg +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/images/logo-text.gif +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/images/logo-text.svg +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/images/logo-white.svg +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/docs/index.md +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/examples/api_router_demo.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/examples/query_list_demo.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/examples/restapi_demo.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/examples/websocket_demo.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/__init__.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/__main__.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/config.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/endpoint.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/models/tag.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/plugins.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/star_openapi/py.typed +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/tests/test_api_router.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/tests/test_query_list.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/tests/test_restapi.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/tests/test_upload_file.py +0 -0
- {star_openapi-0.9.0 → star_openapi-0.9.2}/tests/test_websocket.py +0 -0
|
@@ -3,5 +3,5 @@ Checklist:
|
|
|
3
3
|
- [ ] Run `pytest tests` and no failed.
|
|
4
4
|
- [ ] Run `ruff check star_openapi tests examples` and no failed.
|
|
5
5
|
- [ ] Run `ruff format star_openapi tests examples` and no failed.
|
|
6
|
-
- [ ] Run `
|
|
6
|
+
- [ ] Run `ty check star_openapi` and no failed.
|
|
7
7
|
- [ ] Run `mkdocs serve` and no failed.
|
|
@@ -12,6 +12,8 @@ jobs:
|
|
|
12
12
|
- uses: actions/checkout@v6
|
|
13
13
|
|
|
14
14
|
- uses: astral-sh/setup-uv@v7
|
|
15
|
+
with:
|
|
16
|
+
enable-cache: true
|
|
15
17
|
|
|
16
18
|
- name: Install dependencies
|
|
17
19
|
run: uv sync
|
|
@@ -21,5 +23,5 @@ jobs:
|
|
|
21
23
|
git config --local user.email "action@github.com"
|
|
22
24
|
git config --local user.name "GitHub Action"
|
|
23
25
|
git fetch origin gh-pages:gh-pages
|
|
24
|
-
uv run mike deploy v0.
|
|
26
|
+
uv run mike deploy v0.x latest --update-aliases
|
|
25
27
|
git push origin gh-pages
|
|
@@ -3,17 +3,15 @@ name: tests
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
branches: [ main ]
|
|
6
|
-
paths
|
|
7
|
-
- "
|
|
8
|
-
- "
|
|
9
|
-
- "*.rst"
|
|
6
|
+
paths:
|
|
7
|
+
- "star_openapi/**"
|
|
8
|
+
- "tests/**"
|
|
10
9
|
|
|
11
10
|
pull_request:
|
|
12
11
|
branches: [ main ]
|
|
13
|
-
paths
|
|
14
|
-
- "
|
|
15
|
-
- "
|
|
16
|
-
- "*.rst"
|
|
12
|
+
paths:
|
|
13
|
+
- "star_openapi/**"
|
|
14
|
+
- "tests/**"
|
|
17
15
|
|
|
18
16
|
jobs:
|
|
19
17
|
tests:
|
|
@@ -40,14 +38,11 @@ jobs:
|
|
|
40
38
|
- name: Test with pytest
|
|
41
39
|
run: uv run pytest tests
|
|
42
40
|
|
|
43
|
-
- name: ruff
|
|
41
|
+
- name: ruff check
|
|
44
42
|
run: uv run ruff check star_openapi tests examples
|
|
45
43
|
|
|
46
|
-
- name:
|
|
47
|
-
|
|
48
|
-
with:
|
|
49
|
-
path: ./.mypy_cache
|
|
50
|
-
key: mypy|${{ matrix.python-version }}|${{ hashFiles('pyproject.toml') }}
|
|
44
|
+
- name: ruff format
|
|
45
|
+
run: uv run ruff format --check star_openapi tests examples
|
|
51
46
|
|
|
52
|
-
- name: Run
|
|
53
|
-
run: uv run
|
|
47
|
+
- name: Run ty
|
|
48
|
+
run: uv run ty check star_openapi
|
|
@@ -27,15 +27,16 @@ Before submitting pr, you need to complete the following steps:
|
|
|
27
27
|
ruff check star_openapi tests examples
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
4. Running the
|
|
30
|
+
4. Running the ty
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
|
|
33
|
+
ty check star_openapi
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
5. Building the docs
|
|
37
37
|
|
|
38
|
-
Serve the live docs with [Material for MkDocs](https://github.com/squidfunk/mkdocs-material), and make sure it's
|
|
38
|
+
Serve the live docs with [Material for MkDocs](https://github.com/squidfunk/mkdocs-material), and make sure it's
|
|
39
|
+
correct.
|
|
39
40
|
|
|
40
41
|
```bash
|
|
41
42
|
mkdocs serve
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: star-openapi
|
|
3
|
+
Version: 0.9.2
|
|
4
|
+
Summary: A simple async API framework based on Starlette.
|
|
5
|
+
Project-URL: Homepage, https://github.com/luolingchun/star-openapi
|
|
6
|
+
Project-URL: Documentation, https://luolingchun.github.io/star-openapi
|
|
7
|
+
Maintainer-email: llc <luolingchun@outlook.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Web Environment
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: click>=8.0.0
|
|
23
|
+
Requires-Dist: jinja2>=3.1.2
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: starlette>=0.50.0
|
|
26
|
+
Requires-Dist: uvicorn[standard]>=0.40.0
|
|
27
|
+
Provides-Extra: elements
|
|
28
|
+
Requires-Dist: star-openapi-elements; extra == 'elements'
|
|
29
|
+
Provides-Extra: full
|
|
30
|
+
Requires-Dist: httpx; extra == 'full'
|
|
31
|
+
Requires-Dist: itsdangerous; extra == 'full'
|
|
32
|
+
Requires-Dist: python-multipart; extra == 'full'
|
|
33
|
+
Requires-Dist: pyyaml; extra == 'full'
|
|
34
|
+
Provides-Extra: rapidoc
|
|
35
|
+
Requires-Dist: star-openapi-rapidoc; extra == 'rapidoc'
|
|
36
|
+
Provides-Extra: rapipdf
|
|
37
|
+
Requires-Dist: star-openapi-rapipdf; extra == 'rapipdf'
|
|
38
|
+
Provides-Extra: redoc
|
|
39
|
+
Requires-Dist: star-openapi-redoc; extra == 'redoc'
|
|
40
|
+
Provides-Extra: scalar
|
|
41
|
+
Requires-Dist: star-openapi-scalar; extra == 'scalar'
|
|
42
|
+
Provides-Extra: swagger
|
|
43
|
+
Requires-Dist: star-openapi-swagger; extra == 'swagger'
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
<div align="center">
|
|
47
|
+
<a href="https://luolingchun.github.io/star-openapi/" target="_blank">
|
|
48
|
+
<img class="off-glb" src="https://raw.githubusercontent.com/luolingchun/star-openapi/main/docs/images/logo-text.svg"
|
|
49
|
+
width="60%" height="auto" alt="logo">
|
|
50
|
+
</a>
|
|
51
|
+
</div>
|
|
52
|
+
<p align="center">
|
|
53
|
+
<em>A simple async API framework based on Starlette.</em>
|
|
54
|
+
</p>
|
|
55
|
+
<p align="center">
|
|
56
|
+
<a href="https://github.com/luolingchun/star-openapi/actions/workflows/tests.yml" target="_blank">
|
|
57
|
+
<img class="off-glb" src="https://img.shields.io/github/actions/workflow/status/luolingchun/star-openapi/tests.yml?branch=main" alt="test">
|
|
58
|
+
</a>
|
|
59
|
+
<a href="https://pypi.org/project/star-openapi/" target="_blank">
|
|
60
|
+
<img class="off-glb" src="https://img.shields.io/pypi/v/star-openapi" alt="pypi">
|
|
61
|
+
</a>
|
|
62
|
+
<a href="https://pypistats.org/packages/star-openapi" target="_blank">
|
|
63
|
+
<img class="off-glb" src="https://img.shields.io/pypi/dm/star-openapi" alt="pypistats">
|
|
64
|
+
</a>
|
|
65
|
+
<a href="https://pypi.org/project/star-openapi/" target="_blank">
|
|
66
|
+
<img class="off-glb" src="https://img.shields.io/pypi/pyversions/star-openapi" alt="pypi versions">
|
|
67
|
+
</a>
|
|
68
|
+
</p>
|
|
69
|
+
|
|
70
|
+
**Star OpenAPI** is a web API framework based on **Starlette**. It uses **Pydantic** to verify data and automatic
|
|
71
|
+
generation of interaction documentation.
|
|
72
|
+
|
|
73
|
+
The key features are:
|
|
74
|
+
|
|
75
|
+
- **Easy to code:** Easy to use and easy to learn
|
|
76
|
+
|
|
77
|
+
- **Standard document specification:** Based on [OpenAPI Specification](https://spec.openapis.org/oas/v3.1.0)
|
|
78
|
+
|
|
79
|
+
- **Interactive OpenAPI documentation:**
|
|
80
|
+
[Swagger](https://github.com/swagger-api/swagger-ui), [Redoc](https://github.com/Redocly/redoc), [RapiDoc](https://github.com/rapi-doc/RapiDoc), [RapiPdf](https://mrin9.github.io/RapiPdf/), [Scalar](https://github.com/scalar/scalar), [Elements](https://github.com/stoplightio/elements)
|
|
81
|
+
|
|
82
|
+
- **Data validation:** Fast data verification based on [Pydantic](https://github.com/pydantic/pydantic)
|
|
83
|
+
|
|
84
|
+
- **Websocket**: Support for websocket
|
|
85
|
+
|
|
86
|
+
## Requirements
|
|
87
|
+
|
|
88
|
+
Python 3.11+
|
|
89
|
+
|
|
90
|
+
star-openapi is dependent on the following libraries:
|
|
91
|
+
|
|
92
|
+
- [Starlette](https://github.com/Kludex/starlette) for the web app.
|
|
93
|
+
- [Pydantic](https://github.com/pydantic/pydantic) for the data validation.
|
|
94
|
+
|
|
95
|
+
## Installation
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install -U star-openapi[swagger]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
<details markdown="block">
|
|
102
|
+
<summary>Optional dependencies</summary>
|
|
103
|
+
|
|
104
|
+
- [`httpx`](https://github.com/encode/httpx/) - Required if you want to use the `TestClient`.
|
|
105
|
+
- [`python-multipart`](https://github.com//kludex/python-multipart) - Required if you want to support form parsing, with
|
|
106
|
+
`request.form()`.
|
|
107
|
+
- [`itsdangerous`](https://github.com/pallets/itsdangerous) - Required for `SessionMiddleware` support.
|
|
108
|
+
- [`pyyaml`](https://github.com/yaml/pyyaml) - Required for `SchemaGenerator` support.
|
|
109
|
+
|
|
110
|
+
You can install all of these with `pip install star-openapi[full]`.
|
|
111
|
+
|
|
112
|
+
- [star-openapi-plugins](https://github.com/luolingchun/star-openapi-plugins) Provide OpenAPI UI for star-openapi.
|
|
113
|
+
|
|
114
|
+
You can install all of these with `pip install star-openapi[swagger,redoc,rapidoc,rapipdf,scalar,elements]`.
|
|
115
|
+
|
|
116
|
+
</details>
|
|
117
|
+
|
|
118
|
+
## A Simple Example
|
|
119
|
+
|
|
120
|
+
Here's a simple example, further go to the [Example](https://luolingchun.github.io/star-openapi/v0.x/Example/).
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
import uvicorn
|
|
124
|
+
from pydantic import BaseModel
|
|
125
|
+
from starlette.responses import JSONResponse
|
|
126
|
+
|
|
127
|
+
from star_openapi import OpenAPI
|
|
128
|
+
|
|
129
|
+
info = {"title": "Star API", "version": "1.0.0"}
|
|
130
|
+
app = OpenAPI(info=info)
|
|
131
|
+
|
|
132
|
+
book_tag = {"name": "book", "description": "book tag"}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class BookModel(BaseModel):
|
|
136
|
+
name: str
|
|
137
|
+
age: int
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@app.post("/book", summary="get books", tags=[book_tag])
|
|
141
|
+
async def create_user(body: BookModel):
|
|
142
|
+
"""
|
|
143
|
+
get all books
|
|
144
|
+
"""
|
|
145
|
+
print(body.model_dump_json())
|
|
146
|
+
return JSONResponse({"message": "Hello World"})
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
if __name__ == "__main__":
|
|
150
|
+
print(app.routes)
|
|
151
|
+
uvicorn.run(app)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## API Document
|
|
155
|
+
|
|
156
|
+
Run the [simple example](https://github.com/luolingchun/star-openapi/blob/main/examples/simple_demo.py), and go
|
|
157
|
+
to http://127.0.0.1:8000/openapi.
|
|
158
|
+
|
|
159
|
+
> OpenAPI UI plugins are optional dependencies that require manual installation.
|
|
160
|
+
>
|
|
161
|
+
> `pip install -U star-openapi[swagger,redoc,rapidoc,rapipdf,scalar,elements]`
|
|
162
|
+
>
|
|
163
|
+
> More optional ui templates goto the document
|
|
164
|
+
> about [UI_Templates](https://luolingchun.github.io/star-openapi/v0.x/Usage/UI_Templates/).
|
|
165
|
+
|
|
166
|
+

|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
</a>
|
|
6
6
|
</div>
|
|
7
7
|
<p align="center">
|
|
8
|
-
<em>A simple API framework based on Starlette.</em>
|
|
8
|
+
<em>A simple async API framework based on Starlette.</em>
|
|
9
9
|
</p>
|
|
10
10
|
<p align="center">
|
|
11
11
|
<a href="https://github.com/luolingchun/star-openapi/actions/workflows/tests.yml" target="_blank">
|
|
@@ -36,6 +36,8 @@ The key features are:
|
|
|
36
36
|
|
|
37
37
|
- **Data validation:** Fast data verification based on [Pydantic](https://github.com/pydantic/pydantic)
|
|
38
38
|
|
|
39
|
+
- **Websocket**: Support for websocket
|
|
40
|
+
|
|
39
41
|
## Requirements
|
|
40
42
|
|
|
41
43
|
Python 3.11+
|
|
@@ -85,13 +87,13 @@ app = OpenAPI(info=info)
|
|
|
85
87
|
book_tag = {"name": "book", "description": "book tag"}
|
|
86
88
|
|
|
87
89
|
|
|
88
|
-
class
|
|
90
|
+
class BookModel(BaseModel):
|
|
89
91
|
name: str
|
|
90
92
|
age: int
|
|
91
93
|
|
|
92
94
|
|
|
93
95
|
@app.post("/book", summary="get books", tags=[book_tag])
|
|
94
|
-
async def create_user(body:
|
|
96
|
+
async def create_user(body: BookModel):
|
|
95
97
|
"""
|
|
96
98
|
get all books
|
|
97
99
|
"""
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
## Simple Demo
|
|
2
|
+
|
|
3
|
+
```python
|
|
4
|
+
import uvicorn
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
from starlette.responses import JSONResponse
|
|
7
|
+
|
|
8
|
+
from star_openapi import OpenAPI
|
|
9
|
+
|
|
10
|
+
info = {"title": "Star API", "version": "1.0.0"}
|
|
11
|
+
app = OpenAPI(info=info)
|
|
12
|
+
|
|
13
|
+
book_tag = {"name": "book", "description": "book tag"}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BookModel(BaseModel):
|
|
17
|
+
name: str
|
|
18
|
+
age: int
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@app.get("/book", summary="get books", tags=[book_tag])
|
|
22
|
+
async def get_book(query: BookModel):
|
|
23
|
+
"""
|
|
24
|
+
get all books
|
|
25
|
+
"""
|
|
26
|
+
print(query.model_dump_json())
|
|
27
|
+
return JSONResponse({"message": "Hello World"})
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
if __name__ == "__main__":
|
|
31
|
+
print(app.routes)
|
|
32
|
+
uvicorn.run(app)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## REST Demo
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from http import HTTPStatus
|
|
39
|
+
|
|
40
|
+
from pydantic import BaseModel, Field
|
|
41
|
+
from starlette.responses import JSONResponse
|
|
42
|
+
|
|
43
|
+
from star_openapi import Info, OpenAPI, Tag
|
|
44
|
+
|
|
45
|
+
info = Info(title="book API", version="1.0.0")
|
|
46
|
+
# Basic Authentication Sample
|
|
47
|
+
basic = {"type": "http", "scheme": "basic"}
|
|
48
|
+
# JWT Bearer Sample
|
|
49
|
+
jwt = {"type": "http", "scheme": "bearer", "bearerFormat": "JWT"}
|
|
50
|
+
# API Key Sample
|
|
51
|
+
api_key = {"type": "apiKey", "name": "api_key", "in": "header"}
|
|
52
|
+
# Implicit OAuth2 Sample
|
|
53
|
+
oauth2 = {
|
|
54
|
+
"type": "oauth2",
|
|
55
|
+
"flows": {
|
|
56
|
+
"implicit": {
|
|
57
|
+
"authorizationUrl": "https://example.com/api/oauth/dialog",
|
|
58
|
+
"scopes": {"write:pets": "modify pets in your account", "read:pets": "read your pets"},
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
security_schemes = {"jwt": jwt, "api_key": api_key, "oauth2": oauth2, "basic": basic}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class NotFoundResponse(BaseModel):
|
|
66
|
+
code: int = Field(-1, description="Status Code")
|
|
67
|
+
message: str = Field("Resource not found!", description="Exception Information")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
app = OpenAPI(info=info, security_schemes=security_schemes)
|
|
71
|
+
|
|
72
|
+
book_tag = Tag(name="book", description="Some Book")
|
|
73
|
+
security = [{"jwt": []}, {"oauth2": ["write:pets", "read:pets"]}]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class BookPath(BaseModel):
|
|
77
|
+
id: int = Field(..., description="book id")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class BookQuery(BaseModel):
|
|
81
|
+
age: int | None = Field(None, description="Age")
|
|
82
|
+
s_list: list[str] = Field(None, alias="s_list[]", description="some array")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class BookBody(BaseModel):
|
|
86
|
+
age: int | None = Field(..., ge=2, le=4, description="Age")
|
|
87
|
+
author: str | None = Field(None, min_length=2, max_length=4, description="Author")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class BookBodyWithID(BaseModel):
|
|
91
|
+
id: int = Field(..., description="book id")
|
|
92
|
+
age: int | None = Field(None, ge=2, le=4, description="Age")
|
|
93
|
+
author: str = Field(None, min_length=2, max_length=4, description="Author")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class BookResponse(BaseModel):
|
|
97
|
+
code: int = Field(0, description="Status Code")
|
|
98
|
+
message: str = Field("ok", description="Exception Information")
|
|
99
|
+
data: BookBodyWithID | None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@app.get(
|
|
103
|
+
"/book/{id}",
|
|
104
|
+
tags=[book_tag],
|
|
105
|
+
summary="new summary",
|
|
106
|
+
description="new description",
|
|
107
|
+
security=security,
|
|
108
|
+
)
|
|
109
|
+
async def get_book(path: BookPath):
|
|
110
|
+
"""Get a book
|
|
111
|
+
to get some book by id, like:
|
|
112
|
+
http://localhost:8000/book/3
|
|
113
|
+
"""
|
|
114
|
+
if path.id == 4:
|
|
115
|
+
return NotFoundResponse().model_dump_json(), 404
|
|
116
|
+
return JSONResponse({"code": 0, "message": "ok", "data": {"id": path.id, "age": 3, "author": "no"}})
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# set doc_ui False disable openapi UI
|
|
120
|
+
@app.get("/book", doc_ui=True, deprecated=True)
|
|
121
|
+
async def get_books(query: BookQuery):
|
|
122
|
+
"""get books
|
|
123
|
+
to get all books
|
|
124
|
+
"""
|
|
125
|
+
print(query)
|
|
126
|
+
return JSONResponse(
|
|
127
|
+
{
|
|
128
|
+
"code": 0,
|
|
129
|
+
"message": "ok",
|
|
130
|
+
"data": [{"id": 1, "age": query.age, "author": "a1"}, {"id": 2, "age": query.age, "author": "a2"}],
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@app.post("/book", tags=[book_tag])
|
|
136
|
+
async def create_book(body: BookBody):
|
|
137
|
+
print(body)
|
|
138
|
+
return JSONResponse({"code": 0, "message": "ok"})
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@app.put("/book/{id}", tags=[book_tag])
|
|
142
|
+
async def update_book(path: BookPath, body: BookBody):
|
|
143
|
+
print(path)
|
|
144
|
+
print(body)
|
|
145
|
+
return JSONResponse({"code": 0, "message": "ok"})
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@app.delete("/book/{id}", tags=[book_tag], doc_ui=False)
|
|
149
|
+
async def delete_book(path: BookPath):
|
|
150
|
+
print(path)
|
|
151
|
+
return JSONResponse({"code": 0, "message": "ok"})
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if __name__ == "__main__":
|
|
155
|
+
import uvicorn
|
|
156
|
+
|
|
157
|
+
uvicorn.run(app)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## APIRouter
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
import uvicorn
|
|
164
|
+
from pydantic import BaseModel
|
|
165
|
+
from starlette.responses import JSONResponse
|
|
166
|
+
|
|
167
|
+
from star_openapi import OpenAPI
|
|
168
|
+
from star_openapi.router import APIRouter
|
|
169
|
+
|
|
170
|
+
app = OpenAPI()
|
|
171
|
+
|
|
172
|
+
api1 = APIRouter(url_prefix="/api1")
|
|
173
|
+
api2 = APIRouter(url_prefix="/api2")
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class IdModel(BaseModel):
|
|
177
|
+
id: int
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class BookModel(BaseModel):
|
|
181
|
+
name: str
|
|
182
|
+
age: int
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@api1.get("/book")
|
|
186
|
+
async def ge_book():
|
|
187
|
+
return JSONResponse({"message": "Hello World1"})
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@api1.post("/book")
|
|
191
|
+
async def create_book(body: BookModel):
|
|
192
|
+
return JSONResponse(body.model_dump())
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@api1.put("/book/{id}")
|
|
196
|
+
async def update_book(path: IdModel, body: BookModel):
|
|
197
|
+
return JSONResponse({"id": path.id, "name": body.name, "age": body.age})
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@api1.delete("/book/{id}")
|
|
201
|
+
async def delete_book(path: IdModel):
|
|
202
|
+
return JSONResponse({"id": path.id})
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@api2.get("/")
|
|
206
|
+
async def get_api2():
|
|
207
|
+
return JSONResponse({"message": "Hello World2"})
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
api1.register_api(api2)
|
|
211
|
+
|
|
212
|
+
app.register_api(api1)
|
|
213
|
+
app.register_api(api2)
|
|
214
|
+
|
|
215
|
+
if __name__ == "__main__":
|
|
216
|
+
print(app.routes)
|
|
217
|
+
uvicorn.run(app)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Upload File Demo
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
import uvicorn
|
|
224
|
+
from pydantic import BaseModel, Field
|
|
225
|
+
from starlette.responses import JSONResponse
|
|
226
|
+
|
|
227
|
+
from star_openapi import OpenAPI, UploadFile
|
|
228
|
+
|
|
229
|
+
app = OpenAPI()
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class UploadFileForm(BaseModel):
|
|
233
|
+
file: UploadFile
|
|
234
|
+
file_type: str = Field(None, description="File Type")
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class UploadFilesForm(BaseModel):
|
|
238
|
+
files: list[UploadFile]
|
|
239
|
+
file_type: str = Field(None, description="File Type")
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
@app.post("/upload/file")
|
|
243
|
+
async def upload_file(form: UploadFileForm):
|
|
244
|
+
print(form.file.filename)
|
|
245
|
+
print(form.file_type)
|
|
246
|
+
|
|
247
|
+
content = await form.file.read()
|
|
248
|
+
with open(form.file.filename, "wb") as f:
|
|
249
|
+
f.write(content)
|
|
250
|
+
return JSONResponse({"code": 0, "message": "ok"})
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@app.post("/upload/files")
|
|
254
|
+
async def upload_files(form: UploadFilesForm):
|
|
255
|
+
print(form.files)
|
|
256
|
+
print(form.file_type)
|
|
257
|
+
return JSONResponse({"code": 0, "message": "ok"})
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
if __name__ == "__main__":
|
|
261
|
+
print(app.routes)
|
|
262
|
+
uvicorn.run(app)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Websocket Demo
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
import uvicorn
|
|
269
|
+
from starlette.websockets import WebSocket
|
|
270
|
+
|
|
271
|
+
from star_openapi import OpenAPI
|
|
272
|
+
|
|
273
|
+
app = OpenAPI()
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@app.websocket("/ws")
|
|
277
|
+
async def websocket_endpoint(websocket: WebSocket):
|
|
278
|
+
await websocket.accept()
|
|
279
|
+
while True:
|
|
280
|
+
data = await websocket.receive_text()
|
|
281
|
+
await websocket.send_text(data)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
if __name__ == "__main__":
|
|
285
|
+
uvicorn.run("websocket:app", reload=True)
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## A complete project
|
|
289
|
+
|
|
290
|
+
see [star-api-demo](https://github.com/luolingchun/star-api-demo)
|