Coverage for tests / test_schema_extra_examples.py: 100%
111 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +0000
1import pytest 1ijkl
2from fastapi import Body, Cookie, FastAPI, Header, Path, Query 1ijkl
3from fastapi.exceptions import FastAPIDeprecationWarning 1ijkl
4from fastapi.testclient import TestClient 1ijkl
5from inline_snapshot import snapshot 1ijkl
6from pydantic import BaseModel, ConfigDict 1ijkl
9def create_app(): 1ijkl
10 app = FastAPI() 1aedhbfcg
12 class Item(BaseModel): 1aedhbfcg
13 data: str 1aebfcg
15 model_config = ConfigDict( 1aedhbfcg
16 json_schema_extra={"example": {"data": "Data in schema_extra"}}
17 )
19 @app.post("/schema_extra/") 1aedhbfcg
20 def schema_extra(item: Item): 1aedhbfcg
21 return item 1adbc
23 with pytest.warns(FastAPIDeprecationWarning): 1aedhbfcg
25 @app.post("/example/") 1aedhbfcg
26 def example(item: Item = Body(example={"data": "Data in Body example"})): 1aedhbfcg
27 return item 1adbc
29 @app.post("/examples/") 1aedhbfcg
30 def examples( 1aedhbfcg
31 item: Item = Body(
32 examples=[
33 {"data": "Data in Body examples, example1"},
34 {"data": "Data in Body examples, example2"},
35 ],
36 ),
37 ):
38 return item 1adbc
40 with pytest.warns(FastAPIDeprecationWarning): 1aedhbfcg
42 @app.post("/example_examples/") 1aedhbfcg
43 def example_examples( 1aedhbfcg
44 item: Item = Body(
45 example={"data": "Overridden example"},
46 examples=[
47 {"data": "examples example_examples 1"},
48 {"data": "examples example_examples 2"},
49 ],
50 ),
51 ):
52 return item 1adbc
54 # TODO: enable these tests once/if Form(embed=False) is supported
55 # TODO: In that case, define if File() should support example/examples too
56 # @app.post("/form_example")
57 # def form_example(firstname: str = Form(example="John")):
58 # return firstname
60 # @app.post("/form_examples")
61 # def form_examples(
62 # lastname: str = Form(
63 # ...,
64 # examples={
65 # "example1": {"summary": "last name summary", "value": "Doe"},
66 # "example2": {"value": "Doesn't"},
67 # },
68 # ),
69 # ):
70 # return lastname
72 # @app.post("/form_example_examples")
73 # def form_example_examples(
74 # lastname: str = Form(
75 # ...,
76 # example="Doe overridden",
77 # examples={
78 # "example1": {"summary": "last name summary", "value": "Doe"},
79 # "example2": {"value": "Doesn't"},
80 # },
81 # ),
82 # ):
83 # return lastname
85 with pytest.warns(FastAPIDeprecationWarning): 1aedhbfcg
87 @app.get("/path_example/{item_id}") 1aedhbfcg
88 def path_example( 1aedhbfcg
89 item_id: str = Path(
90 example="item_1",
91 ),
92 ):
93 return item_id 1adbc
95 @app.get("/path_examples/{item_id}") 1aedhbfcg
96 def path_examples( 1aedhbfcg
97 item_id: str = Path(
98 examples=["item_1", "item_2"],
99 ),
100 ):
101 return item_id 1adbc
103 with pytest.warns(FastAPIDeprecationWarning): 1aedhbfcg
105 @app.get("/path_example_examples/{item_id}") 1aedhbfcg
106 def path_example_examples( 1aedhbfcg
107 item_id: str = Path(
108 example="item_overridden",
109 examples=["item_1", "item_2"],
110 ),
111 ):
112 return item_id 1adbc
114 with pytest.warns(FastAPIDeprecationWarning): 1aedhbfcg
116 @app.get("/query_example/") 1aedhbfcg
117 def query_example( 1aedhbfcg
118 data: str | None = Query(
119 default=None,
120 example="query1",
121 ),
122 ):
123 return data 1adbc
125 @app.get("/query_examples/") 1aedhbfcg
126 def query_examples( 1aedhbfcg
127 data: str | None = Query(
128 default=None,
129 examples=["query1", "query2"],
130 ),
131 ):
132 return data 1adbc
134 with pytest.warns(FastAPIDeprecationWarning): 1aedhbfcg
136 @app.get("/query_example_examples/") 1aedhbfcg
137 def query_example_examples( 1aedhbfcg
138 data: str | None = Query(
139 default=None,
140 example="query_overridden",
141 examples=["query1", "query2"],
142 ),
143 ):
144 return data 1adbc
146 with pytest.warns(FastAPIDeprecationWarning): 1aedhbfcg
148 @app.get("/header_example/") 1aedhbfcg
149 def header_example( 1aedhbfcg
150 data: str | None = Header(
151 default=None,
152 example="header1",
153 ),
154 ):
155 return data 1adbc
157 @app.get("/header_examples/") 1aedhbfcg
158 def header_examples( 1aedhbfcg
159 data: str | None = Header(
160 default=None,
161 examples=[
162 "header1",
163 "header2",
164 ],
165 ),
166 ):
167 return data 1adbc
169 with pytest.warns(FastAPIDeprecationWarning): 1aedhbfcg
171 @app.get("/header_example_examples/") 1aedhbfcg
172 def header_example_examples( 1aedhbfcg
173 data: str | None = Header(
174 default=None,
175 example="header_overridden",
176 examples=["header1", "header2"],
177 ),
178 ):
179 return data 1adbc
181 with pytest.warns(FastAPIDeprecationWarning): 1aedhbfcg
183 @app.get("/cookie_example/") 1aedhbfcg
184 def cookie_example( 1aedhbfcg
185 data: str | None = Cookie(
186 default=None,
187 example="cookie1",
188 ),
189 ):
190 return data 1adbc
192 @app.get("/cookie_examples/") 1aedhbfcg
193 def cookie_examples( 1aedhbfcg
194 data: str | None = Cookie(
195 default=None,
196 examples=["cookie1", "cookie2"],
197 ),
198 ):
199 return data 1adbc
201 with pytest.warns(FastAPIDeprecationWarning): 1aedhbfcg
203 @app.get("/cookie_example_examples/") 1aedhbfcg
204 def cookie_example_examples( 1aedhbfcg
205 data: str | None = Cookie(
206 default=None,
207 example="cookie_overridden",
208 examples=["cookie1", "cookie2"],
209 ),
210 ):
211 return data 1adbc
213 return app 1aedhbfcg
216def test_call_api(): 1ijkl
217 app = create_app() 1adbc
218 client = TestClient(app) 1adbc
219 response = client.post("/schema_extra/", json={"data": "Foo"}) 1adbc
220 assert response.status_code == 200, response.text 1adbc
221 response = client.post("/example/", json={"data": "Foo"}) 1adbc
222 assert response.status_code == 200, response.text 1adbc
223 response = client.post("/examples/", json={"data": "Foo"}) 1adbc
224 assert response.status_code == 200, response.text 1adbc
225 response = client.post("/example_examples/", json={"data": "Foo"}) 1adbc
226 assert response.status_code == 200, response.text 1adbc
227 response = client.get("/path_example/foo") 1adbc
228 assert response.status_code == 200, response.text 1adbc
229 response = client.get("/path_examples/foo") 1adbc
230 assert response.status_code == 200, response.text 1adbc
231 response = client.get("/path_example_examples/foo") 1adbc
232 assert response.status_code == 200, response.text 1adbc
233 response = client.get("/query_example/") 1adbc
234 assert response.status_code == 200, response.text 1adbc
235 response = client.get("/query_examples/") 1adbc
236 assert response.status_code == 200, response.text 1adbc
237 response = client.get("/query_example_examples/") 1adbc
238 assert response.status_code == 200, response.text 1adbc
239 response = client.get("/header_example/") 1adbc
240 assert response.status_code == 200, response.text 1adbc
241 response = client.get("/header_examples/") 1adbc
242 assert response.status_code == 200, response.text 1adbc
243 response = client.get("/header_example_examples/") 1adbc
244 assert response.status_code == 200, response.text 1adbc
245 response = client.get("/cookie_example/") 1adbc
246 assert response.status_code == 200, response.text 1adbc
247 response = client.get("/cookie_examples/") 1adbc
248 assert response.status_code == 200, response.text 1adbc
249 response = client.get("/cookie_example_examples/") 1adbc
250 assert response.status_code == 200, response.text 1adbc
253def test_openapi_schema(): 1ijkl
254 """
255 Test that example overrides work:
257 * pydantic model schema_extra is included
258 * Body(example={}) overrides schema_extra in pydantic model
259 * Body(examples{}) overrides Body(example={}) and schema_extra in pydantic model
260 """
261 app = create_app() 1ehfg
262 client = TestClient(app) 1ehfg
263 response = client.get("/openapi.json") 1ehfg
264 assert response.status_code == 200, response.text 1ehfg
265 assert response.json() == snapshot( 1ehfg
266 {
267 "openapi": "3.1.0",
268 "info": {"title": "FastAPI", "version": "0.1.0"},
269 "paths": {
270 "/schema_extra/": {
271 "post": {
272 "summary": "Schema Extra",
273 "operationId": "schema_extra_schema_extra__post",
274 "requestBody": {
275 "content": {
276 "application/json": {
277 "schema": {"$ref": "#/components/schemas/Item"}
278 }
279 },
280 "required": True,
281 },
282 "responses": {
283 "200": {
284 "description": "Successful Response",
285 "content": {"application/json": {"schema": {}}},
286 },
287 "422": {
288 "description": "Validation Error",
289 "content": {
290 "application/json": {
291 "schema": {
292 "$ref": "#/components/schemas/HTTPValidationError"
293 }
294 }
295 },
296 },
297 },
298 }
299 },
300 "/example/": {
301 "post": {
302 "summary": "Example",
303 "operationId": "example_example__post",
304 "requestBody": {
305 "content": {
306 "application/json": {
307 "schema": {"$ref": "#/components/schemas/Item"},
308 "example": {"data": "Data in Body example"},
309 }
310 },
311 "required": True,
312 },
313 "responses": {
314 "200": {
315 "description": "Successful Response",
316 "content": {"application/json": {"schema": {}}},
317 },
318 "422": {
319 "description": "Validation Error",
320 "content": {
321 "application/json": {
322 "schema": {
323 "$ref": "#/components/schemas/HTTPValidationError"
324 }
325 }
326 },
327 },
328 },
329 }
330 },
331 "/examples/": {
332 "post": {
333 "summary": "Examples",
334 "operationId": "examples_examples__post",
335 "requestBody": {
336 "content": {
337 "application/json": {
338 "schema": {
339 "$ref": "#/components/schemas/Item",
340 "examples": [
341 {"data": "Data in Body examples, example1"},
342 {"data": "Data in Body examples, example2"},
343 ],
344 }
345 }
346 },
347 "required": True,
348 },
349 "responses": {
350 "200": {
351 "description": "Successful Response",
352 "content": {"application/json": {"schema": {}}},
353 },
354 "422": {
355 "description": "Validation Error",
356 "content": {
357 "application/json": {
358 "schema": {
359 "$ref": "#/components/schemas/HTTPValidationError"
360 }
361 }
362 },
363 },
364 },
365 }
366 },
367 "/example_examples/": {
368 "post": {
369 "summary": "Example Examples",
370 "operationId": "example_examples_example_examples__post",
371 "requestBody": {
372 "content": {
373 "application/json": {
374 "schema": {
375 "$ref": "#/components/schemas/Item",
376 "examples": [
377 {"data": "examples example_examples 1"},
378 {"data": "examples example_examples 2"},
379 ],
380 },
381 "example": {"data": "Overridden example"},
382 }
383 },
384 "required": True,
385 },
386 "responses": {
387 "200": {
388 "description": "Successful Response",
389 "content": {"application/json": {"schema": {}}},
390 },
391 "422": {
392 "description": "Validation Error",
393 "content": {
394 "application/json": {
395 "schema": {
396 "$ref": "#/components/schemas/HTTPValidationError"
397 }
398 }
399 },
400 },
401 },
402 }
403 },
404 "/path_example/{item_id}": {
405 "get": {
406 "summary": "Path Example",
407 "operationId": "path_example_path_example__item_id__get",
408 "parameters": [
409 {
410 "required": True,
411 "schema": {"title": "Item Id", "type": "string"},
412 "example": "item_1",
413 "name": "item_id",
414 "in": "path",
415 }
416 ],
417 "responses": {
418 "200": {
419 "description": "Successful Response",
420 "content": {"application/json": {"schema": {}}},
421 },
422 "422": {
423 "description": "Validation Error",
424 "content": {
425 "application/json": {
426 "schema": {
427 "$ref": "#/components/schemas/HTTPValidationError"
428 }
429 }
430 },
431 },
432 },
433 }
434 },
435 "/path_examples/{item_id}": {
436 "get": {
437 "summary": "Path Examples",
438 "operationId": "path_examples_path_examples__item_id__get",
439 "parameters": [
440 {
441 "required": True,
442 "schema": {
443 "title": "Item Id",
444 "type": "string",
445 "examples": ["item_1", "item_2"],
446 },
447 "name": "item_id",
448 "in": "path",
449 }
450 ],
451 "responses": {
452 "200": {
453 "description": "Successful Response",
454 "content": {"application/json": {"schema": {}}},
455 },
456 "422": {
457 "description": "Validation Error",
458 "content": {
459 "application/json": {
460 "schema": {
461 "$ref": "#/components/schemas/HTTPValidationError"
462 }
463 }
464 },
465 },
466 },
467 }
468 },
469 "/path_example_examples/{item_id}": {
470 "get": {
471 "summary": "Path Example Examples",
472 "operationId": "path_example_examples_path_example_examples__item_id__get",
473 "parameters": [
474 {
475 "required": True,
476 "schema": {
477 "title": "Item Id",
478 "type": "string",
479 "examples": ["item_1", "item_2"],
480 },
481 "example": "item_overridden",
482 "name": "item_id",
483 "in": "path",
484 }
485 ],
486 "responses": {
487 "200": {
488 "description": "Successful Response",
489 "content": {"application/json": {"schema": {}}},
490 },
491 "422": {
492 "description": "Validation Error",
493 "content": {
494 "application/json": {
495 "schema": {
496 "$ref": "#/components/schemas/HTTPValidationError"
497 }
498 }
499 },
500 },
501 },
502 }
503 },
504 "/query_example/": {
505 "get": {
506 "summary": "Query Example",
507 "operationId": "query_example_query_example__get",
508 "parameters": [
509 {
510 "required": False,
511 "schema": {
512 "anyOf": [{"type": "string"}, {"type": "null"}],
513 "title": "Data",
514 },
515 "example": "query1",
516 "name": "data",
517 "in": "query",
518 }
519 ],
520 "responses": {
521 "200": {
522 "description": "Successful Response",
523 "content": {"application/json": {"schema": {}}},
524 },
525 "422": {
526 "description": "Validation Error",
527 "content": {
528 "application/json": {
529 "schema": {
530 "$ref": "#/components/schemas/HTTPValidationError"
531 }
532 }
533 },
534 },
535 },
536 }
537 },
538 "/query_examples/": {
539 "get": {
540 "summary": "Query Examples",
541 "operationId": "query_examples_query_examples__get",
542 "parameters": [
543 {
544 "required": False,
545 "schema": {
546 "anyOf": [{"type": "string"}, {"type": "null"}],
547 "title": "Data",
548 "examples": ["query1", "query2"],
549 },
550 "name": "data",
551 "in": "query",
552 }
553 ],
554 "responses": {
555 "200": {
556 "description": "Successful Response",
557 "content": {"application/json": {"schema": {}}},
558 },
559 "422": {
560 "description": "Validation Error",
561 "content": {
562 "application/json": {
563 "schema": {
564 "$ref": "#/components/schemas/HTTPValidationError"
565 }
566 }
567 },
568 },
569 },
570 }
571 },
572 "/query_example_examples/": {
573 "get": {
574 "summary": "Query Example Examples",
575 "operationId": "query_example_examples_query_example_examples__get",
576 "parameters": [
577 {
578 "required": False,
579 "schema": {
580 "anyOf": [{"type": "string"}, {"type": "null"}],
581 "title": "Data",
582 "examples": ["query1", "query2"],
583 },
584 "example": "query_overridden",
585 "name": "data",
586 "in": "query",
587 }
588 ],
589 "responses": {
590 "200": {
591 "description": "Successful Response",
592 "content": {"application/json": {"schema": {}}},
593 },
594 "422": {
595 "description": "Validation Error",
596 "content": {
597 "application/json": {
598 "schema": {
599 "$ref": "#/components/schemas/HTTPValidationError"
600 }
601 }
602 },
603 },
604 },
605 }
606 },
607 "/header_example/": {
608 "get": {
609 "summary": "Header Example",
610 "operationId": "header_example_header_example__get",
611 "parameters": [
612 {
613 "required": False,
614 "schema": {
615 "anyOf": [{"type": "string"}, {"type": "null"}],
616 "title": "Data",
617 },
618 "example": "header1",
619 "name": "data",
620 "in": "header",
621 }
622 ],
623 "responses": {
624 "200": {
625 "description": "Successful Response",
626 "content": {"application/json": {"schema": {}}},
627 },
628 "422": {
629 "description": "Validation Error",
630 "content": {
631 "application/json": {
632 "schema": {
633 "$ref": "#/components/schemas/HTTPValidationError"
634 }
635 }
636 },
637 },
638 },
639 }
640 },
641 "/header_examples/": {
642 "get": {
643 "summary": "Header Examples",
644 "operationId": "header_examples_header_examples__get",
645 "parameters": [
646 {
647 "required": False,
648 "schema": {
649 "anyOf": [{"type": "string"}, {"type": "null"}],
650 "title": "Data",
651 "examples": ["header1", "header2"],
652 },
653 "name": "data",
654 "in": "header",
655 }
656 ],
657 "responses": {
658 "200": {
659 "description": "Successful Response",
660 "content": {"application/json": {"schema": {}}},
661 },
662 "422": {
663 "description": "Validation Error",
664 "content": {
665 "application/json": {
666 "schema": {
667 "$ref": "#/components/schemas/HTTPValidationError"
668 }
669 }
670 },
671 },
672 },
673 }
674 },
675 "/header_example_examples/": {
676 "get": {
677 "summary": "Header Example Examples",
678 "operationId": "header_example_examples_header_example_examples__get",
679 "parameters": [
680 {
681 "required": False,
682 "schema": {
683 "anyOf": [{"type": "string"}, {"type": "null"}],
684 "title": "Data",
685 "examples": ["header1", "header2"],
686 },
687 "example": "header_overridden",
688 "name": "data",
689 "in": "header",
690 }
691 ],
692 "responses": {
693 "200": {
694 "description": "Successful Response",
695 "content": {"application/json": {"schema": {}}},
696 },
697 "422": {
698 "description": "Validation Error",
699 "content": {
700 "application/json": {
701 "schema": {
702 "$ref": "#/components/schemas/HTTPValidationError"
703 }
704 }
705 },
706 },
707 },
708 }
709 },
710 "/cookie_example/": {
711 "get": {
712 "summary": "Cookie Example",
713 "operationId": "cookie_example_cookie_example__get",
714 "parameters": [
715 {
716 "required": False,
717 "schema": {
718 "anyOf": [{"type": "string"}, {"type": "null"}],
719 "title": "Data",
720 },
721 "example": "cookie1",
722 "name": "data",
723 "in": "cookie",
724 }
725 ],
726 "responses": {
727 "200": {
728 "description": "Successful Response",
729 "content": {"application/json": {"schema": {}}},
730 },
731 "422": {
732 "description": "Validation Error",
733 "content": {
734 "application/json": {
735 "schema": {
736 "$ref": "#/components/schemas/HTTPValidationError"
737 }
738 }
739 },
740 },
741 },
742 }
743 },
744 "/cookie_examples/": {
745 "get": {
746 "summary": "Cookie Examples",
747 "operationId": "cookie_examples_cookie_examples__get",
748 "parameters": [
749 {
750 "required": False,
751 "schema": {
752 "anyOf": [{"type": "string"}, {"type": "null"}],
753 "title": "Data",
754 "examples": ["cookie1", "cookie2"],
755 },
756 "name": "data",
757 "in": "cookie",
758 }
759 ],
760 "responses": {
761 "200": {
762 "description": "Successful Response",
763 "content": {"application/json": {"schema": {}}},
764 },
765 "422": {
766 "description": "Validation Error",
767 "content": {
768 "application/json": {
769 "schema": {
770 "$ref": "#/components/schemas/HTTPValidationError"
771 }
772 }
773 },
774 },
775 },
776 }
777 },
778 "/cookie_example_examples/": {
779 "get": {
780 "summary": "Cookie Example Examples",
781 "operationId": "cookie_example_examples_cookie_example_examples__get",
782 "parameters": [
783 {
784 "required": False,
785 "schema": {
786 "anyOf": [{"type": "string"}, {"type": "null"}],
787 "title": "Data",
788 "examples": ["cookie1", "cookie2"],
789 },
790 "example": "cookie_overridden",
791 "name": "data",
792 "in": "cookie",
793 }
794 ],
795 "responses": {
796 "200": {
797 "description": "Successful Response",
798 "content": {"application/json": {"schema": {}}},
799 },
800 "422": {
801 "description": "Validation Error",
802 "content": {
803 "application/json": {
804 "schema": {
805 "$ref": "#/components/schemas/HTTPValidationError"
806 }
807 }
808 },
809 },
810 },
811 }
812 },
813 },
814 "components": {
815 "schemas": {
816 "HTTPValidationError": {
817 "title": "HTTPValidationError",
818 "type": "object",
819 "properties": {
820 "detail": {
821 "title": "Detail",
822 "type": "array",
823 "items": {
824 "$ref": "#/components/schemas/ValidationError"
825 },
826 }
827 },
828 },
829 "Item": {
830 "title": "Item",
831 "required": ["data"],
832 "type": "object",
833 "properties": {"data": {"title": "Data", "type": "string"}},
834 "example": {"data": "Data in schema_extra"},
835 },
836 "ValidationError": {
837 "title": "ValidationError",
838 "required": ["loc", "msg", "type"],
839 "type": "object",
840 "properties": {
841 "loc": {
842 "title": "Location",
843 "type": "array",
844 "items": {
845 "anyOf": [{"type": "string"}, {"type": "integer"}]
846 },
847 },
848 "msg": {"title": "Message", "type": "string"},
849 "type": {"title": "Error Type", "type": "string"},
850 "input": {"title": "Input"},
851 "ctx": {"title": "Context", "type": "object"},
852 },
853 },
854 }
855 },
856 }
857 )