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