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

1from typing import Union 1ghij

2 

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

9 

10 

11def create_app(): 1ghij

12 app = FastAPI() 1adbecf

13 

14 class Item(BaseModel): 1adbecf

15 data: str 1adbecf

16 

17 model_config = ConfigDict( 1adbecf

18 json_schema_extra={"example": {"data": "Data in schema_extra"}} 

19 ) 

20 

21 @app.post("/schema_extra/") 1adbecf

22 def schema_extra(item: Item): 1adbecf

23 return item 1abc

24 

25 with pytest.warns(FastAPIDeprecationWarning): 1adbecf

26 

27 @app.post("/example/") 1adbecf

28 def example(item: Item = Body(example={"data": "Data in Body example"})): 1adbecf

29 return item 1abc

30 

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

41 

42 with pytest.warns(FastAPIDeprecationWarning): 1adbecf

43 

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

55 

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 

61 

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 

73 

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 

86 

87 with pytest.warns(FastAPIDeprecationWarning): 1adbecf

88 

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

96 

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

104 

105 with pytest.warns(FastAPIDeprecationWarning): 1adbecf

106 

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

115 

116 with pytest.warns(FastAPIDeprecationWarning): 1adbecf

117 

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

126 

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

135 

136 with pytest.warns(FastAPIDeprecationWarning): 1adbecf

137 

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

147 

148 with pytest.warns(FastAPIDeprecationWarning): 1adbecf

149 

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

158 

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

170 

171 with pytest.warns(FastAPIDeprecationWarning): 1adbecf

172 

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

182 

183 with pytest.warns(FastAPIDeprecationWarning): 1adbecf

184 

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

193 

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

202 

203 with pytest.warns(FastAPIDeprecationWarning): 1adbecf

204 

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

214 

215 return app 1adbecf

216 

217 

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

253 

254 

255def test_openapi_schema(): 1ghij

256 """ 

257 Test that example overrides work: 

258 

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 )