@@ -11,3 +11,258 @@ Operations are a serialized form of the mutations allowed in the base JSON:API s
1111
1212Clients can send an array of operations in a single request.
1313This extension guarantees that those operations will be processed in order and will either completely succeed or fail together.
14+
15+
16+ What can I do?
17+ --------------
18+
19+ Atomic operations extension supports these three actions:
20+
21+ * ``add `` - create a new object
22+ * ``update `` - update any existing object
23+ * ``remove `` - delete any existing object
24+
25+ You can send one or more atomic operations in one request.
26+
27+ If anything fails in one of the operations, everything will be rolled back.
28+
29+ .. note ::
30+ Only SQLAlchemy data layer supports atomic operations right now.
31+ Feel free to send PRs to add support for other data layers.
32+
33+
34+ Configuration
35+ -------------
36+
37+ You need to include atomic router:
38+
39+ .. code-block :: python
40+
41+ from fastapi import FastAPI
42+ from fastapi_jsonapi.atomic import AtomicOperations
43+
44+
45+ def add_routes (app : FastAPI):
46+ atomic = AtomicOperations()
47+ app.include_router(atomic.router)
48+
49+ Default path for atomic operations is ``/operations ``
50+
51+
52+ There's a way to customize url path, you can also pass your custom APIRouter:
53+
54+ .. code-block :: python
55+
56+ from fastapi import APIRouter
57+ from fastapi_jsonapi.atomic import AtomicOperations
58+
59+ my_router = APIRouter(prefix = " /qwerty" , tags = [" Atomic Operations" ])
60+
61+ AtomicOperations(
62+ # you can pass custom url path
63+ url_path = " /atomic" ,
64+ # also you can pass your custom router
65+ router = my_router,
66+ )
67+
68+
69+ Create some objects
70+ -------------------
71+
72+ Create two objects, they are not linked anyhow:
73+
74+ Request:
75+
76+ .. literalinclude :: ./http_snippets/snippets/example_atomic_one__create_computer_and_separate_user
77+ :language: HTTP
78+
79+ Response:
80+
81+ .. literalinclude :: ./http_snippets/snippets/example_atomic_one__create_computer_and_separate_user_result
82+ :language: HTTP
83+
84+
85+
86+ Update object
87+ -------------
88+
89+ Update details
90+ ^^^^^^^^^^^^^^
91+
92+ Atomic operations array has to contain at least one operation.
93+ Body in each atomic action has to be as in other regular requests.
94+ For example, update any existing object:
95+
96+
97+ .. literalinclude :: ./http_snippets/snippets/example_atomic_two__update_user
98+ :language: HTTP
99+
100+ Response:
101+
102+ .. literalinclude :: ./http_snippets/snippets/example_atomic_two__update_user_result
103+ :language: HTTP
104+
105+
106+ Update details and relationships
107+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
108+
109+ .. warning ::
110+ There may be issues when updating to-many relationships. This feature is not fully-tested yet.
111+
112+ Update already any existing computer and link it to any existing user:
113+
114+
115+ Request:
116+
117+ .. literalinclude :: ./http_snippets/snippets/example_atomic_two__update_computer
118+ :language: HTTP
119+
120+ Response:
121+
122+ .. literalinclude :: ./http_snippets/snippets/example_atomic_two__update_computer_result
123+ :language: HTTP
124+
125+
126+ You can check that details and relationships are updated by fetching the object and related objects:
127+
128+
129+ Request:
130+
131+ .. literalinclude :: ./http_snippets/snippets/example_atomic_two__after_update_computer_check_details
132+ :language: HTTP
133+
134+ Response:
135+
136+ .. literalinclude :: ./http_snippets/snippets/example_atomic_two__after_update_computer_check_details_result
137+ :language: HTTP
138+
139+
140+
141+ Remove object
142+ -------------
143+
144+ You can mix any actions, for example you can create, update, remove at the same time:
145+
146+
147+ Request:
148+
149+ .. literalinclude :: ./http_snippets/snippets/example_atomic_five__mixed_actions
150+ :language: HTTP
151+
152+ Response:
153+
154+ .. literalinclude :: ./http_snippets/snippets/example_atomic_five__mixed_actions_result
155+ :language: HTTP
156+
157+
158+ If all actions are to delete objects, empty response will be returned:
159+
160+
161+ Request:
162+
163+ .. literalinclude :: ./http_snippets/snippets/example_atomic_five__only_remove_actions
164+ :language: HTTP
165+
166+ Response:
167+
168+ .. literalinclude :: ./http_snippets/snippets/example_atomic_five__only_remove_actions_result
169+ :language: HTTP
170+
171+
172+
173+ Local identifier
174+ ----------------
175+
176+ Sometimes you need to create an object, create another object and link it to the first one:
177+
178+ Create user and create bio for this user:
179+
180+ Request:
181+
182+ .. literalinclude :: ./http_snippets/snippets/example_atomic_three__create_user_and_user_bio
183+ :language: HTTP
184+
185+ Response:
186+
187+ .. literalinclude :: ./http_snippets/snippets/example_atomic_three__create_user_and_user_bio_result
188+ :language: HTTP
189+
190+
191+
192+ Many to many with local identifier
193+ ----------------------------------
194+
195+ If you have many-to-many association (:ref: `examples with many-to-many <include_many_to_many >`),
196+ atomic operations should look like this:
197+
198+
199+ Request:
200+
201+ .. literalinclude :: ./http_snippets/snippets/example_atomic_four__create_many-to-many
202+ :language: HTTP
203+
204+ Response:
205+
206+ .. literalinclude :: ./http_snippets/snippets/example_atomic_four__create_many-to-many_result
207+ :language: HTTP
208+
209+
210+ Check that objects and relationships were created. Pass includes in the url path, like this
211+ ``/parent-to-child-association/1?include=parent,child ``
212+
213+
214+ Request:
215+
216+ .. literalinclude :: ./http_snippets/snippets/example_atomic_four__get-many-to-many_with_includes
217+ :language: HTTP
218+
219+ Response:
220+
221+ .. literalinclude :: ./http_snippets/snippets/example_atomic_four__get-many-to-many_with_includes_result
222+ :language: HTTP
223+
224+
225+
226+
227+ Errors
228+ ------
229+
230+ If any action on the operations list fails, everything will be rolled back
231+ and an error will be returned. Example:
232+
233+
234+ Request:
235+
236+ .. literalinclude :: ./http_snippets/snippets/example_atomic_fail__create_computer_and_update_user_bio
237+ :language: HTTP
238+
239+ Response:
240+
241+ .. literalinclude :: ./http_snippets/snippets/example_atomic_fail__create_computer_and_update_user_bio_result
242+ :language: HTTP
243+
244+
245+ Since ``update `` action requires ``id `` field and user-bio update schema requires ``birth_city `` field,
246+ the app rollbacks all actions and computer is not saved in DB (and user-bio is not updated).
247+
248+ Error is not in JSON:API style yet, PRs are welcome.
249+
250+
251+ Notes
252+ -----
253+
254+
255+ .. note ::
256+ See `examples for SQLAlchemy <SQLA_examples >`_ in the repo, all examples are based on it.
257+
258+
259+ .. warning ::
260+ Field "href" is not supported yet. Resource can be referenced only by the "type" field.
261+
262+ Relationships resources are not implemented yet,
263+ so updating relationships directly through atomic operations
264+ is not supported too (see skipped tests).
265+
266+ Includes in the response body are not supported (and not planned, until you PR it)
267+
268+ .. _SQLA_examples : https://github.com/mts-ai/FastAPI-JSONAPI/tree/main/examples/api_for_sqlalchemy
0 commit comments