Coverage for tests/test_extra_routes.py: 100%
64 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-08 03:53 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-08 03:53 +0000
1from typing import Optional 1abcde
3from dirty_equals import IsDict 1abcde
4from fastapi import FastAPI 1abcde
5from fastapi.responses import JSONResponse 1abcde
6from fastapi.testclient import TestClient 1abcde
7from pydantic import BaseModel 1abcde
9app = FastAPI() 1abcde
12class Item(BaseModel): 1abcde
13 name: str 1abcde
14 price: Optional[float] = None 1abcde
17@app.api_route("/items/{item_id}", methods=["GET"]) 1abcde
18def get_items(item_id: str): 1abcde
19 return {"item_id": item_id} 1abcde
22def get_not_decorated(item_id: str): 1abcde
23 return {"item_id": item_id} 1abcde
26app.add_api_route("/items-not-decorated/{item_id}", get_not_decorated) 1abcde
29@app.delete("/items/{item_id}") 1abcde
30def delete_item(item_id: str, item: Item): 1abcde
31 return {"item_id": item_id, "item": item} 1abcde
34@app.head("/items/{item_id}") 1abcde
35def head_item(item_id: str): 1abcde
36 return JSONResponse(None, headers={"x-fastapi-item-id": item_id}) 1abcde
39@app.options("/items/{item_id}") 1abcde
40def options_item(item_id: str): 1abcde
41 return JSONResponse(None, headers={"x-fastapi-item-id": item_id}) 1abcde
44@app.patch("/items/{item_id}") 1abcde
45def patch_item(item_id: str, item: Item): 1abcde
46 return {"item_id": item_id, "item": item} 1abcde
49@app.trace("/items/{item_id}") 1abcde
50def trace_item(item_id: str): 1abcde
51 return JSONResponse(None, media_type="message/http") 1abcde
54client = TestClient(app) 1abcde
57def test_get_api_route(): 1abcde
58 response = client.get("/items/foo") 1abcde
59 assert response.status_code == 200, response.text 1abcde
60 assert response.json() == {"item_id": "foo"} 1abcde
63def test_get_api_route_not_decorated(): 1abcde
64 response = client.get("/items-not-decorated/foo") 1abcde
65 assert response.status_code == 200, response.text 1abcde
66 assert response.json() == {"item_id": "foo"} 1abcde
69def test_delete(): 1abcde
70 response = client.request("DELETE", "/items/foo", json={"name": "Foo"}) 1abcde
71 assert response.status_code == 200, response.text 1abcde
72 assert response.json() == {"item_id": "foo", "item": {"name": "Foo", "price": None}} 1abcde
75def test_head(): 1abcde
76 response = client.head("/items/foo") 1abcde
77 assert response.status_code == 200, response.text 1abcde
78 assert response.headers["x-fastapi-item-id"] == "foo" 1abcde
81def test_options(): 1abcde
82 response = client.options("/items/foo") 1abcde
83 assert response.status_code == 200, response.text 1abcde
84 assert response.headers["x-fastapi-item-id"] == "foo" 1abcde
87def test_patch(): 1abcde
88 response = client.patch("/items/foo", json={"name": "Foo"}) 1abcde
89 assert response.status_code == 200, response.text 1abcde
90 assert response.json() == {"item_id": "foo", "item": {"name": "Foo", "price": None}} 1abcde
93def test_trace(): 1abcde
94 response = client.request("trace", "/items/foo") 1abcde
95 assert response.status_code == 200, response.text 1abcde
96 assert response.headers["content-type"] == "message/http" 1abcde
99def test_openapi_schema(): 1abcde
100 response = client.get("/openapi.json") 1abcde
101 assert response.status_code == 200, response.text 1abcde
102 assert response.json() == { 1abcde
103 "openapi": "3.1.0",
104 "info": {"title": "FastAPI", "version": "0.1.0"},
105 "paths": {
106 "/items/{item_id}": {
107 "get": {
108 "responses": {
109 "200": {
110 "description": "Successful Response",
111 "content": {"application/json": {"schema": {}}},
112 },
113 "422": {
114 "description": "Validation Error",
115 "content": {
116 "application/json": {
117 "schema": {
118 "$ref": "#/components/schemas/HTTPValidationError"
119 }
120 }
121 },
122 },
123 },
124 "summary": "Get Items",
125 "operationId": "get_items_items__item_id__get",
126 "parameters": [
127 {
128 "required": True,
129 "schema": {"title": "Item Id", "type": "string"},
130 "name": "item_id",
131 "in": "path",
132 }
133 ],
134 },
135 "delete": {
136 "responses": {
137 "200": {
138 "description": "Successful Response",
139 "content": {"application/json": {"schema": {}}},
140 },
141 "422": {
142 "description": "Validation Error",
143 "content": {
144 "application/json": {
145 "schema": {
146 "$ref": "#/components/schemas/HTTPValidationError"
147 }
148 }
149 },
150 },
151 },
152 "summary": "Delete Item",
153 "operationId": "delete_item_items__item_id__delete",
154 "parameters": [
155 {
156 "required": True,
157 "schema": {"title": "Item Id", "type": "string"},
158 "name": "item_id",
159 "in": "path",
160 }
161 ],
162 "requestBody": {
163 "content": {
164 "application/json": {
165 "schema": {"$ref": "#/components/schemas/Item"}
166 }
167 },
168 "required": True,
169 },
170 },
171 "options": {
172 "responses": {
173 "200": {
174 "description": "Successful Response",
175 "content": {"application/json": {"schema": {}}},
176 },
177 "422": {
178 "description": "Validation Error",
179 "content": {
180 "application/json": {
181 "schema": {
182 "$ref": "#/components/schemas/HTTPValidationError"
183 }
184 }
185 },
186 },
187 },
188 "summary": "Options Item",
189 "operationId": "options_item_items__item_id__options",
190 "parameters": [
191 {
192 "required": True,
193 "schema": {"title": "Item Id", "type": "string"},
194 "name": "item_id",
195 "in": "path",
196 }
197 ],
198 },
199 "head": {
200 "responses": {
201 "200": {
202 "description": "Successful Response",
203 "content": {"application/json": {"schema": {}}},
204 },
205 "422": {
206 "description": "Validation Error",
207 "content": {
208 "application/json": {
209 "schema": {
210 "$ref": "#/components/schemas/HTTPValidationError"
211 }
212 }
213 },
214 },
215 },
216 "summary": "Head Item",
217 "operationId": "head_item_items__item_id__head",
218 "parameters": [
219 {
220 "required": True,
221 "schema": {"title": "Item Id", "type": "string"},
222 "name": "item_id",
223 "in": "path",
224 }
225 ],
226 },
227 "patch": {
228 "responses": {
229 "200": {
230 "description": "Successful Response",
231 "content": {"application/json": {"schema": {}}},
232 },
233 "422": {
234 "description": "Validation Error",
235 "content": {
236 "application/json": {
237 "schema": {
238 "$ref": "#/components/schemas/HTTPValidationError"
239 }
240 }
241 },
242 },
243 },
244 "summary": "Patch Item",
245 "operationId": "patch_item_items__item_id__patch",
246 "parameters": [
247 {
248 "required": True,
249 "schema": {"title": "Item Id", "type": "string"},
250 "name": "item_id",
251 "in": "path",
252 }
253 ],
254 "requestBody": {
255 "content": {
256 "application/json": {
257 "schema": {"$ref": "#/components/schemas/Item"}
258 }
259 },
260 "required": True,
261 },
262 },
263 "trace": {
264 "responses": {
265 "200": {
266 "description": "Successful Response",
267 "content": {"application/json": {"schema": {}}},
268 },
269 "422": {
270 "description": "Validation Error",
271 "content": {
272 "application/json": {
273 "schema": {
274 "$ref": "#/components/schemas/HTTPValidationError"
275 }
276 }
277 },
278 },
279 },
280 "summary": "Trace Item",
281 "operationId": "trace_item_items__item_id__trace",
282 "parameters": [
283 {
284 "required": True,
285 "schema": {"title": "Item Id", "type": "string"},
286 "name": "item_id",
287 "in": "path",
288 }
289 ],
290 },
291 },
292 "/items-not-decorated/{item_id}": {
293 "get": {
294 "responses": {
295 "200": {
296 "description": "Successful Response",
297 "content": {"application/json": {"schema": {}}},
298 },
299 "422": {
300 "description": "Validation Error",
301 "content": {
302 "application/json": {
303 "schema": {
304 "$ref": "#/components/schemas/HTTPValidationError"
305 }
306 }
307 },
308 },
309 },
310 "summary": "Get Not Decorated",
311 "operationId": "get_not_decorated_items_not_decorated__item_id__get",
312 "parameters": [
313 {
314 "required": True,
315 "schema": {"title": "Item Id", "type": "string"},
316 "name": "item_id",
317 "in": "path",
318 }
319 ],
320 }
321 },
322 },
323 "components": {
324 "schemas": {
325 "Item": {
326 "title": "Item",
327 "required": ["name"],
328 "type": "object",
329 "properties": {
330 "name": {"title": "Name", "type": "string"},
331 "price": IsDict(
332 {
333 "title": "Price",
334 "anyOf": [{"type": "number"}, {"type": "null"}],
335 }
336 )
337 # TODO: remove when deprecating Pydantic v1
338 | IsDict({"title": "Price", "type": "number"}),
339 },
340 },
341 "ValidationError": {
342 "title": "ValidationError",
343 "required": ["loc", "msg", "type"],
344 "type": "object",
345 "properties": {
346 "loc": {
347 "title": "Location",
348 "type": "array",
349 "items": {
350 "anyOf": [{"type": "string"}, {"type": "integer"}]
351 },
352 },
353 "msg": {"title": "Message", "type": "string"},
354 "type": {"title": "Error Type", "type": "string"},
355 },
356 },
357 "HTTPValidationError": {
358 "title": "HTTPValidationError",
359 "type": "object",
360 "properties": {
361 "detail": {
362 "title": "Detail",
363 "type": "array",
364 "items": {"$ref": "#/components/schemas/ValidationError"},
365 }
366 },
367 },
368 }
369 },
370 }