@@ -21,9 +21,9 @@ Some of them are worth sharing.
21
21
- [ Prefer ` async ` dependencies] ( #prefer-async-dependencies )
22
22
- [ Miscellaneous] ( #miscellaneous )
23
23
- [ Follow the REST] ( #follow-the-rest )
24
- - [ ValueErrors might become Pydantic ValidationError] ( #valueerrors-might-become-pydantic-validationerror )
25
- - [ If you must use sync SDK, then run it in a thread pool.] ( #if-you-must-use-sync-sdk-then-run-it-in-a-thread-pool )
26
24
- [ FastAPI response serialization] ( #fastapi-response-serialization )
25
+ - [ If you must use sync SDK, then run it in a thread pool.] ( #if-you-must-use-sync-sdk-then-run-it-in-a-thread-pool )
26
+ - [ ValueErrors might become Pydantic ValidationError] ( #valueerrors-might-become-pydantic-validationerror )
27
27
- [ Docs] ( #docs )
28
28
- [ Set DB keys naming conventions] ( #set-db-keys-naming-conventions )
29
29
- [ Migrations. Alembic] ( #migrations-alembic )
@@ -507,44 +507,36 @@ async def get_user_profile_by_id(
507
507
return creator_profile
508
508
509
509
```
510
+ ### FastAPI response serialization
511
+ If you think you can return Pydantic object that matches your route's ` response_model ` to make some optimizations,
512
+ then it's wrong.
510
513
511
- ### ValueErrors might become Pydantic ValidationError
512
- If you raise a ` ValueError ` in a Pydantic schema that is directly faced by the client, it will return a nice detailed response to users.
514
+ FastAPI firstly converts that pydantic object to dict with its ` jsonable_encoder ` , then validates
515
+ data with your ` response_model ` , and only then serializes your object to JSON.
513
516
``` python
514
- # src.profiles.schemas
515
- from pydantic import BaseModel, field_validator
516
-
517
- class ProfileCreate (BaseModel ):
518
- username: str
519
-
520
- @field_validator (" password" , mode = " after" )
521
- @ classmethod
522
- def valid_password (cls , password : str ) -> str :
523
- if not re.match(STRONG_PASSWORD_PATTERN , password):
524
- raise ValueError (
525
- " Password must contain at least "
526
- " one lower character, "
527
- " one upper character, "
528
- " digit or "
529
- " special symbol"
530
- )
517
+ from fastapi import FastAPI
518
+ from pydantic import BaseModel, root_validator
531
519
532
- return password
520
+ app = FastAPI()
533
521
534
522
535
- # src.profiles.routes
536
- from fastapi import APIRouter
523
+ class ProfileResponse (BaseModel ):
524
+ @model_validator (mode = " after" )
525
+ def debug_usage (self ):
526
+ print (" created pydantic model" )
537
527
538
- router = APIRouter()
528
+ return self
539
529
540
530
541
- @router.post (" /profiles" )
542
- async def get_creator_posts (profile_data : ProfileCreate):
543
- pass
531
+ @app.get (" /" , response_model = ProfileResponse)
532
+ async def root ():
533
+ return ProfileResponse()
534
+ ```
535
+ ** Logs Output:**
536
+ ```
537
+ [INFO] [2022-08-28 12:00:00.000000] created pydantic model
538
+ [INFO] [2022-08-28 12:00:00.000020] created pydantic model
544
539
```
545
- ** Response Example:**
546
-
547
- <img src =" images/value_error_response.png " width =" 400 " height =" auto " >
548
540
549
541
### If you must use sync SDK, then run it in a thread pool.
550
542
If you must use a library to interact with external services, and it's not ` async ` ,
@@ -567,36 +559,43 @@ async def call_my_sync_library():
567
559
await run_in_threadpool(client.make_request, data = my_data)
568
560
```
569
561
570
- ### FastAPI response serialization
571
- If you think you can return Pydantic object that matches your route's ` response_model ` to make some optimizations,
572
- then it's wrong.
573
-
574
- FastAPI firstly converts that pydantic object to dict with its ` jsonable_encoder ` , then validates
575
- data with your ` response_model ` , and only then serializes your object to JSON.
562
+ ### ValueErrors might become Pydantic ValidationError
563
+ If you raise a ` ValueError ` in a Pydantic schema that is directly faced by the client, it will return a nice detailed response to users.
576
564
``` python
577
- from fastapi import FastAPI
578
- from pydantic import BaseModel, root_validator
565
+ # src.profiles.schemas
566
+ from pydantic import BaseModel, field_validator
579
567
580
- app = FastAPI()
568
+ class ProfileCreate (BaseModel ):
569
+ username: str
570
+
571
+ @field_validator (" password" , mode = " after" )
572
+ @ classmethod
573
+ def valid_password (cls , password : str ) -> str :
574
+ if not re.match(STRONG_PASSWORD_PATTERN , password):
575
+ raise ValueError (
576
+ " Password must contain at least "
577
+ " one lower character, "
578
+ " one upper character, "
579
+ " digit or "
580
+ " special symbol"
581
+ )
581
582
583
+ return password
582
584
583
- class ProfileResponse (BaseModel ):
584
- @model_validator (mode = " after" )
585
- def debug_usage (self ):
586
- print (" created pydantic model" )
587
585
588
- return self
586
+ # src.profiles.routes
587
+ from fastapi import APIRouter
589
588
589
+ router = APIRouter()
590
590
591
- @app.get (" /" , response_model = ProfileResponse)
592
- async def root ():
593
- return ProfileResponse()
594
- ```
595
- ** Logs Output:**
596
- ```
597
- [INFO] [2022-08-28 12:00:00.000000] created pydantic model
598
- [INFO] [2022-08-28 12:00:00.000020] created pydantic model
591
+
592
+ @router.post (" /profiles" )
593
+ async def get_creator_posts (profile_data : ProfileCreate):
594
+ pass
599
595
```
596
+ ** Response Example:**
597
+
598
+ <img src =" images/value_error_response.png " width =" 400 " height =" auto " >
600
599
601
600
### Docs
602
601
1 . Unless your API is public, hide docs by default. Show it explicitly on the selected envs only.
0 commit comments