Skip to content

Commit 84db4cd

Browse files
VishnuSanalsansyroxtavallaie
authored
feat: openapi implementation (#890)
* demo for upcoming openapi and validations * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * feat[WIP]: openapi * feat(openapi): update * feat(openapi): add to all methods * feat(openapi): add resposne * feat(openapi): initial schema * feat(openapi): fix path param issue * use docstring as summary * add servers and ext docs objects to spec * add schema component objects to spec * refactor openapi code & move to a class * cleanup & [WIP] openapi implementation for subrouters * revert ugly implementation of openapi for subrouters * better impl for subrouters * add types and docstrings * review comments: cleanup * handle query params using typed dict ;___; * use data classes * address review comment suggestions * move openapi example to integration tests * fix path param isue * add docstrings for dataclasses * add tests for openapi * chore: cleanup * add docs for openapi on the website * Update robyn/openapi.py Co-authored-by: Sanskar Jethi <[email protected]> * Update robyn/openapi.py Co-authored-by: Sanskar Jethi <[email protected]> * Update robyn/openapi.py Co-authored-by: Sanskar Jethi <[email protected]> * chore: cleanup as per review comments * chore: move json dump to a new function * add integration tests * add tags to subrouter * add typing to docs * Apply suggestions from code review Co-authored-by: Sanskar Jethi <[email protected]> * add docs to api ref * fix typing on docs * fix docstrings on robyn class methods * isort imports * add types to docstrings on openapi.py * update and refactor `openapi#get_path_obj` function * add return types to openapi.py * fix ci: remove `string#removesuffix` (not present in `python3.8`) * review comments * Apply suggestions from code review Co-authored-by: Sanskar Jethi <[email protected]> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix import * update docs * add example app back * updarte test * update default tags * add type to opneapi init in subrotuer * update json handler * fix tests * retrigger ci * Apply suggestions from code review Co-authored-by: Sanskar Jethi <[email protected]> * fix typing * add summary fallback value * rename handlers * better type inference logic! * update tests to not use ast * fix(ci): revert to use typing types (https://stackoverflow.com/a/75202688/9652621) * Apply suggestions from code review Co-authored-by: Sanskar Jethi <[email protected]> * add path param type info to docs * fix typing on openapi.py file * move example back to docs * change version in docs example app * remve path param from routes with query params * update server Co-authored-by: Ali Tavallaie <[email protected]> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Sanskar Jethi <[email protected]> Co-authored-by: Ali Tavallaie <[email protected]>
1 parent 1d555c9 commit 84db4cd

File tree

13 files changed

+989
-50
lines changed

13 files changed

+989
-50
lines changed

docs_src/src/components/documentation/ApiDocs.jsx

+6
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ const guides = [
106106
name: 'GraphQL Support',
107107
description: 'Learn about GraphQL Support in Robyn.',
108108
},
109+
{
110+
href: '/documentation/api_reference/openapi',
111+
name: 'OpenAPI Documentation',
112+
description:
113+
'Learn how to generate OpenAPI docs for your applications.',
114+
},
109115
{
110116
href: '/documentation/api_reference/dependency_injection',
111117
name: 'Dependency Injection',

docs_src/src/components/documentation/Guides.jsx

+6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ const guides = [
3434
description:
3535
'Learn how to deploy your app to production and manage your deployments.',
3636
},
37+
{
38+
href: '/documentation/example_app/openapi',
39+
name: 'OpenAPI Documentation',
40+
description:
41+
'Learn how OpenAPI docs are generate for your applications.',
42+
},
3743
]
3844

3945
export function Guides() {

docs_src/src/components/documentation/Navigation.jsx

+8
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ export const navigation = [
210210
href: '/documentation/example_app/monitoring_and_logging',
211211
},
212212
{ title: 'Deployment', href: '/documentation/example_app/deployment' },
213+
{
214+
title: 'OpenAPI Documentation',
215+
href: '/documentation/example_app/openapi',
216+
},
213217
{ title: 'Templates', href: '/documentation/example_app/templates' },
214218
{
215219
title: 'SubRouters and Views',
@@ -293,6 +297,10 @@ export const navigation = [
293297
href: '/documentation/api_reference/advanced_features',
294298
title: 'Advanced Features',
295299
},
300+
{
301+
title: 'OpenAPI Documentation',
302+
href: '/documentation/api_reference/openapi',
303+
},
296304
{
297305
href: '/documentation/api_reference/multiprocess_execution',
298306
title: 'Multiprocess Execution',

docs_src/src/pages/documentation/api_reference/advanced_features.mdx

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ Batman scaled his application across multiple cores for better performance. He u
3434
## What's next?
3535

3636

37-
Batman wondered about whether Robyn handlers can be dispatched to multiple processes.
37+
Batman wondered about how to help users explore the endpoints in his application.
3838

39-
Robyn showed him the way!
39+
Robyn showed him the OpenAPI Documentation!
4040

41-
[Multitiprocess Execution](/documentation/api_reference/multiprocess_execution)
41+
[Multitiprocess Execution](/documentation/api_reference/openapi)
4242

4343

4444

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
export const description =
2+
'Welcome to the Robyn API documentation. You will find comprehensive guides and documentation to help you start working with Robyn as quickly as possible, as well as support if you get stuck.'
3+
4+
5+
## OpenAPI Docs
6+
7+
After deploying the application, Batman got multiple queries from the users on how to use the endpoints. Robyn showed him how to generate OpenAPI specifications for his application.
8+
9+
Out of the box, the following endpoints are setup for you:
10+
11+
- `/docs` The Swagger UI
12+
- `/openapi.json` The JSON Specification
13+
14+
## How to use?
15+
16+
- Query Params: The typing for query params can be added as `def get(r: Request, query_params=GetRequestParams)` where `GetRequestParams` is a `TypedDict`
17+
- Path Params are defaulted to string type (ref: https://en.wikipedia.org/wiki/Query_string)
18+
19+
<CodeGroup title="Basic App">
20+
21+
```python {{ title: 'untyped' }}
22+
from typing import TypedDict
23+
24+
from robyn import Robyn, OpenAPI
25+
from robyn.openapi import OpenAPIInfo, Contact, License, ExternalDocumentation, Components
26+
27+
app = Robyn(
28+
file_object=__file__,
29+
openapi=OpenAPI(
30+
info=OpenAPIInfo(
31+
title="Sample App",
32+
description="This is a sample server application.",
33+
termsOfService="https://example.com/terms/",
34+
version="1.0.0",
35+
contact=Contact(
36+
name="API Support",
37+
url="https://www.example.com/support",
38+
39+
),
40+
license=License(
41+
name="BSD2.0",
42+
url="https://opensource.org/license/bsd-2-clause",
43+
),
44+
externalDocs=ExternalDocumentation(description="Find more info here", url="https://example.com/"),
45+
components=Components(),
46+
),
47+
),
48+
)
49+
50+
51+
@app.get("/")
52+
async def welcome():
53+
"""welcome endpoint"""
54+
return "hi"
55+
56+
57+
class GetRequestParams(TypedDict):
58+
appointment_id: str
59+
year: int
60+
61+
62+
@app.get("/api/v1/name", openapi_tags=["Name"])
63+
async def get(r, query_params=GetRequestParams):
64+
"""Get Name by ID"""
65+
return r.query_params
66+
67+
68+
@app.delete("/users/:name", openapi_tags=["Name"])
69+
async def delete(r):
70+
"""Delete Name by ID"""
71+
return r.path_params
72+
73+
74+
if __name__ == "__main__":
75+
app.start()
76+
```
77+
78+
```python {{ title: 'typed' }}
79+
from typing import TypedDict
80+
81+
from robyn import Robyn, OpenAPI, Request
82+
from robyn.openapi import OpenAPIInfo, Contact, License, ExternalDocumentation, Components
83+
84+
app: Robyn = Robyn(
85+
file_object=__file__,
86+
openapi=OpenAPI(
87+
info=OpenAPIInfo(
88+
title="Sample App",
89+
description="This is a sample server application.",
90+
termsOfService="https://example.com/terms/",
91+
version="1.0.0",
92+
contact=Contact(
93+
name="API Support",
94+
url="https://www.example.com/support",
95+
96+
),
97+
license=License(
98+
name="BSD2.0",
99+
url="https://opensource.org/license/bsd-2-clause",
100+
),
101+
externalDocs=ExternalDocumentation(description="Find more info here", url="https://example.com/"),
102+
components=Components(),
103+
),
104+
),
105+
)
106+
107+
108+
@app.get("/")
109+
async def welcome():
110+
"""welcome endpoint"""
111+
return "hi"
112+
113+
114+
class GetRequestParams(TypedDict):
115+
appointment_id: str
116+
year: int
117+
118+
119+
@app.get("/api/v1/name", openapi_tags=["Name"])
120+
async def get(r: Request, query_params=GetRequestParams):
121+
"""Get Name by ID"""
122+
return r.query_params
123+
124+
125+
@app.delete("/users/:name", openapi_tags=["Name"])
126+
async def delete(r: Request):
127+
"""Delete Name by ID"""
128+
return r.path_params
129+
130+
131+
if __name__ == "__main__":
132+
app.start()
133+
```
134+
135+
</CodeGroup>
136+
137+
## How does it work with subrouters?
138+
139+
<CodeGroup title="Subrouters">
140+
141+
```python {{ title: 'untyped' }}
142+
from typing import TypedDict
143+
144+
from robyn import SubRouter
145+
146+
subrouter = SubRouter(__name__, prefix="/sub")
147+
148+
149+
@subrouter.get("/")
150+
async def subrouter_welcome():
151+
"""welcome subrouter"""
152+
return "hiiiiii subrouter"
153+
154+
155+
class SubRouterGetRequestParams(TypedDict):
156+
_id: int
157+
value: str
158+
159+
160+
@subrouter.get("/name")
161+
async def subrouter_get(r, query_params=SubRouterGetRequestParams):
162+
"""Get Name by ID"""
163+
return r.query_params
164+
165+
166+
@subrouter.delete("/:name")
167+
async def subrouter_delete(r):
168+
"""Delete Name by ID"""
169+
return r.path_params
170+
171+
172+
app.include_router(subrouter)
173+
```
174+
175+
```python {{ title: 'typed' }}
176+
from typing import TypedDict
177+
178+
from robyn import Request, SubRouter
179+
180+
subrouter: SubRouter = SubRouter(__name__, prefix="/sub")
181+
182+
183+
@subrouter.get("/")
184+
async def subrouter_welcome():
185+
"""welcome subrouter"""
186+
return "hiiiiii subrouter"
187+
188+
189+
class SubRouterGetRequestParams(TypedDict):
190+
_id: int
191+
value: str
192+
193+
194+
@subrouter.get("/name")
195+
async def subrouter_get(r: Request, query_params=SubRouterGetRequestParams):
196+
"""Get Name by ID"""
197+
return r.query_params
198+
199+
200+
@subrouter.delete("/:name")
201+
async def subrouter_delete(r: Request):
202+
"""Delete Name by ID"""
203+
return r.path_params
204+
205+
206+
app.include_router(subrouter)
207+
```
208+
209+
</CodeGroup>
210+
211+
With the reference documentation deployed and running smoothly, Batman had a powerful new tool at his disposal. The Robyn framework had provided him with the flexibility, scalability, and performance needed to create an effective crime-fighting application, giving him a technological edge in his ongoing battle to protect Gotham City.
212+
213+
214+
## What's next?
215+
216+
217+
Batman wondered about whether Robyn handlers can be dispatched to multiple processes.
218+
219+
Robyn showed him the way!
220+
221+
[Multitiprocess Execution](/documentation/api_reference/multiprocess_execution)
222+
223+
224+

docs_src/src/pages/documentation/example_app/deployment.mdx

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ With the web application deployed and running smoothly, Batman had a powerful ne
1616

1717
<div className="not-prose">
1818
<Button
19-
href="/documentation/example_app/templates"
19+
href="/documentation/example_app/openapi"
2020
variant="text"
2121
arrow="right"
22-
children="Templates"
22+
children="OpenAPI Docs"
2323
/>
2424
</div>
2525

0 commit comments

Comments
 (0)