Skip to content

Commit e3d3a58

Browse files
committed
upgrade, fixes, new docs
1 parent d071159 commit e3d3a58

28 files changed

Lines changed: 605 additions & 188 deletions

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,12 @@ class UserDetail:
114114
return UserSchema.from_orm(user)
115115

116116
@classmethod
117-
async def patch(cls, obj_id: int, data: UserPatchSchema, session: AsyncSession = Depends(Connector.get_session)) -> UserSchema:
117+
async def patch(
118+
cls,
119+
obj_id: int,
120+
data: UserPatchSchema,
121+
session: AsyncSession = Depends(Connector.get_session),
122+
) -> UserSchema:
118123
user: User = (await session.execute(select(User).where(User.id == obj_id))).scalar_one()
119124
user.first_name = data.first_name
120125
await session.commit()
@@ -130,7 +135,9 @@ class UserDetail:
130135
class UserList:
131136
@classmethod
132137
async def get(
133-
cls, query_params: QueryStringManager, session: AsyncSession = Depends(Connector.get_session)
138+
cls,
139+
query_params: QueryStringManager,
140+
session: AsyncSession = Depends(Connector.get_session),
134141
) -> Union[Select, JSONAPIResultListSchema]:
135142
user_query = select(User)
136143
dl = SqlalchemyEngine(query=user_query, schema=UserSchema, model=User, session=session)
@@ -160,7 +167,7 @@ def add_routes(app: FastAPI) -> List[Dict[str, Any]]:
160167

161168
routers: APIRouter = APIRouter()
162169
RoutersJSONAPI(
163-
routers=routers,
170+
router=routers,
164171
path="/user",
165172
tags=["User"],
166173
class_detail=UserDetail,
@@ -205,7 +212,6 @@ def create_app() -> FastAPI:
205212

206213
app = create_app()
207214

208-
209215
if __name__ == "__main__":
210216
uvicorn.run(
211217
"test:app",

docs/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
extensions = [
3434
"sphinx.ext.autodoc",
3535
"sphinx.ext.autosummary",
36+
"sphinx.ext.autosectionlabel",
3637
]
3738

3839
# Add any paths that contain templates here, relative to this directory.

docs/http_snippets/README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33

44
## Install
55

6-
> Waiting for a PR to be merged: https://github.com/Kong/httpsnippet/pull/222
7-
>
8-
> Otherwise, extra options cannot be passed
9-
> (you'll need to delete Host and Content-Length manually, or use the forked version)
106

117
```shell
128
# to use in cli
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"method": "GET",
3+
"url": "http://localhost:8082/parents?include=children,children.child",
4+
"httpVersion": "HTTP/1.1",
5+
"queryString": [
6+
],
7+
"headers": [
8+
{
9+
"name": "content-type",
10+
"value": "application/vnd.api+json"
11+
}
12+
]
13+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
GET /parents?include=children%2Cchildren.child HTTP/1.1
2+
Content-Type: application/vnd.api+json
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
HTTP/1.1 200 OK
2+
Content-Type: application/json
3+
4+
{
5+
"data": [
6+
{
7+
"attributes": {
8+
"name": "parent_1"
9+
},
10+
"id": "1",
11+
"relationships": {
12+
"children": {
13+
"data": [
14+
{
15+
"id": "1",
16+
"type": "parent_child_association"
17+
},
18+
{
19+
"id": "3",
20+
"type": "parent_child_association"
21+
}
22+
]
23+
}
24+
},
25+
"type": "parent"
26+
},
27+
{
28+
"attributes": {
29+
"name": "parent_2"
30+
},
31+
"id": "2",
32+
"relationships": {
33+
"children": {
34+
"data": [
35+
{
36+
"id": "2",
37+
"type": "parent_child_association"
38+
},
39+
{
40+
"id": "4",
41+
"type": "parent_child_association"
42+
},
43+
{
44+
"id": "5",
45+
"type": "parent_child_association"
46+
}
47+
]
48+
}
49+
},
50+
"type": "parent"
51+
},
52+
{
53+
"attributes": {
54+
"name": "parent_3"
55+
},
56+
"id": "3",
57+
"relationships": {
58+
"children": {
59+
"data": []
60+
}
61+
},
62+
"type": "parent"
63+
}
64+
],
65+
"included": [
66+
{
67+
"attributes": {
68+
"name": "child_1"
69+
},
70+
"id": "1",
71+
"type": "child"
72+
},
73+
{
74+
"attributes": {
75+
"name": "child_2"
76+
},
77+
"id": "2",
78+
"type": "child"
79+
},
80+
{
81+
"attributes": {
82+
"name": "child_3"
83+
},
84+
"id": "3",
85+
"type": "child"
86+
},
87+
{
88+
"attributes": {
89+
"extra_data": "assoc_p1c1_extra"
90+
},
91+
"id": "1",
92+
"relationships": {
93+
"child": {
94+
"data": {
95+
"id": "1",
96+
"type": "child"
97+
}
98+
}
99+
},
100+
"type": "parent_child_association"
101+
},
102+
{
103+
"attributes": {
104+
"extra_data": "assoc_p2c1_extra"
105+
},
106+
"id": "2",
107+
"relationships": {
108+
"child": {
109+
"data": {
110+
"id": "1",
111+
"type": "child"
112+
}
113+
}
114+
},
115+
"type": "parent_child_association"
116+
},
117+
{
118+
"attributes": {
119+
"extra_data": "assoc_p1c2_extra"
120+
},
121+
"id": "3",
122+
"relationships": {
123+
"child": {
124+
"data": {
125+
"id": "2",
126+
"type": "child"
127+
}
128+
}
129+
},
130+
"type": "parent_child_association"
131+
},
132+
{
133+
"attributes": {
134+
"extra_data": "assoc_p2c2_extra"
135+
},
136+
"id": "4",
137+
"relationships": {
138+
"child": {
139+
"data": {
140+
"id": "2",
141+
"type": "child"
142+
}
143+
}
144+
},
145+
"type": "parent_child_association"
146+
},
147+
{
148+
"attributes": {
149+
"extra_data": "assoc_p2c3_extra"
150+
},
151+
"id": "5",
152+
"relationships": {
153+
"child": {
154+
"data": {
155+
"id": "3",
156+
"type": "child"
157+
}
158+
}
159+
},
160+
"type": "parent_child_association"
161+
}
162+
],
163+
"jsonapi": {
164+
"version": "1.0"
165+
},
166+
"meta": {
167+
"count": 3,
168+
"totalPages": 1
169+
}
170+
}

docs/include_many_to_many.rst

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
.. _include_many_to_many:
2+
3+
Include related M2M
4+
===================
5+
6+
.. currentmodule:: fastapi_jsonapi
7+
8+
The same as usual includes. Here's an example with an association object:
9+
10+
Example (sources `here <https://github.com/mts-ai/FastAPI-JSONAPI/tree/main/examples/api_for_sqlalchemy>`_):
11+
12+
13+
Define SQLAlchemy models
14+
~~~~~~~~~~~~~~~~~~~~~~~~
15+
16+
Parent:
17+
18+
.. literalinclude:: ../examples/api_for_sqlalchemy/models/parent.py
19+
:language: python
20+
21+
22+
Child:
23+
24+
.. literalinclude:: ../examples/api_for_sqlalchemy/models/child.py
25+
:language: python
26+
27+
28+
Parent to Child Association object:
29+
30+
.. literalinclude:: ../examples/api_for_sqlalchemy/models/parent_child_association.py
31+
:language: python
32+
33+
34+
35+
Define pydantic schemas
36+
~~~~~~~~~~~~~~~~~~~~~~~
37+
38+
39+
Parent Schema:
40+
41+
.. literalinclude:: ../examples/api_for_sqlalchemy/models/schemas/parent.py
42+
:language: python
43+
44+
45+
Child Schema:
46+
47+
.. literalinclude:: ../examples/api_for_sqlalchemy/models/schemas/child.py
48+
:language: python
49+
50+
51+
Parent to Child Association Schema:
52+
53+
.. literalinclude:: ../examples/api_for_sqlalchemy/models/schemas/parent_child_association.py
54+
:language: python
55+
56+
57+
58+
59+
List Parent objects with Children through an Association object
60+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
61+
62+
Request:
63+
64+
.. literalinclude:: ./http_snippets/snippets/includes__many_to_many
65+
:language: HTTP
66+
67+
Response:
68+
69+
.. literalinclude:: ./http_snippets/snippets/includes__many_to_many_result
70+
:language: HTTP

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ FastAPI-JSONAPI with FastAPI.
5959
routing
6060
filtering
6161
include_related_objects
62+
include_many_to_many
6263
sparse_fieldsets
6364
pagination
6465
sorting

docs/quickstart.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ around a small tutorial that uses the SQLAlchemy data layer.
1515
This tutorial shows you an example of a person and their computers.
1616

1717
Advanced example
18-
-------------
18+
----------------
1919

2020
An example of FastAPI-JSONAPI API looks like this:
2121

22-
.. literalinclude:: ../examples/api_for_sqlalchemy
22+
.. literalinclude:: ../examples/api_for_sqlalchemy/urls.py
2323
:language: python
2424

2525
This example provides the following API:
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from fastapi import Depends
2+
from sqlalchemy.ext.asyncio import AsyncSession
3+
4+
from examples.api_for_sqlalchemy.extensions.sqlalchemy import Connector
5+
from fastapi_jsonapi import SqlalchemyEngine
6+
from fastapi_jsonapi.querystring import QueryStringManager
7+
from fastapi_jsonapi.schema import JSONAPIResultDetailSchema, JSONAPIResultListSchema
8+
from fastapi_jsonapi.views.detail_view import DetailViewBase
9+
from fastapi_jsonapi.views.list_view import ListViewBase
10+
11+
12+
class DetailViewBaseGeneric(DetailViewBase):
13+
async def get(
14+
self,
15+
obj_id,
16+
query_params: QueryStringManager,
17+
session: AsyncSession = Depends(Connector.get_session),
18+
) -> JSONAPIResultDetailSchema:
19+
dl = SqlalchemyEngine(
20+
schema=self.jsonapi.schema_detail,
21+
model=self.jsonapi.model,
22+
session=session,
23+
)
24+
view_kwargs = {"id": obj_id}
25+
return await self.get_detailed_result(
26+
dl=dl,
27+
view_kwargs=view_kwargs,
28+
query_params=query_params,
29+
)
30+
31+
32+
class ListViewBaseGeneric(ListViewBase):
33+
async def get(
34+
self,
35+
query_params: QueryStringManager,
36+
session: AsyncSession = Depends(Connector.get_session),
37+
) -> JSONAPIResultListSchema:
38+
dl = SqlalchemyEngine(
39+
schema=self.jsonapi.schema_list,
40+
model=self.jsonapi.model,
41+
session=session,
42+
)
43+
return await self.get_paginated_result(
44+
dl=dl,
45+
query_params=query_params,
46+
)

0 commit comments

Comments
 (0)