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