Lời mở đầu
Chào các bạn, hôm nay tôi xin giới thiệu với các bạn về 1 framework API mà tôi mới vọc vạch mấy tuần trước. Tại sao tôi lại giới thiệu framework này, âu cũng là do cái slogan của team này bắt mắt quá.
FastAPI framework, high performance, easy to learn, fast to code, ready for production
Vậy fastAPI là gì, mời các bạn đọc phần tiếp theo.
Khái niệm
FastApi là 1 web framework dùng để build API có hiệu năng cao, code dễ ẹc, đơn giản nhưng cũng hỗ trợ tốt cho việc làm sản phẩm.
Đặc điểm:
- Fast: Hiệu suất cao ngang với NodeJS và Go.
- Fast to code: Code nhanh hơn, tốc độ code các features tăng khoảng 200 đến 300 %.
- Fewer bugs: do đơn giản nên giảm số bugs của developper đến 40%.
- Intuitive: hỗ trợ code dễ hơn với tự động gợi ý, debug cần ít thời gian hơn so với trước.
- Easy: được thiết kế sao cho dễ dùng dễ học.
- Short: Tối thiểu việc lặp code. Các tham số truyền vào có nhiều tính năng. Ít bugs.
- Robust: hiệu năng mạnh mẽ, có thể tương tác API qua docs.
Cài đặt
Yêu cầu: Python 3.6+.
FastAPI được build dựa trên OpenAPI (trước có tên Swagger), phần web được support bởi Starlette, còn phần data được support bởi Pydantic.
FastAPI CLI
Để cài đặt framework này trên Ubuntu, bạn cần phiên bản python ≥geq≥ 3.6.
1 2 | pip install fastapi |
Bạn cũng cần ASGI server khi deploy sản phẩm như Uvicorn hoặc Hypercorn.
1 2 | pip install uvicorn |
Nói sơ qua về ASGI 1 chút, ASGI kế thừa từ WSGI. Mà WSGI là 1 chuẩn giao tiếp giữa web server và Python application server. Trước thì có mod_python của Apache nhưng do không phát triển và không an toàn nên WSGI sinh ra. WSGI có những tác dụng như sau:
- WSGI mang tính linh hoạt: dev có thể chuyển đổi thành phần web như chuyển từ Gunicorn sang uWSGI.
- WSGI xử lý nhiều request cùng lúc thay webserver và quyết định request nào được chuyển tới application web.
Hình minh họa chôm được ở trang (fullstackpython.com):
Nếu như WSGI là tiêu chuẩn cho các synchronous Python apps
thì ASGI là tiêu chuẩn cho cả synchronous
và asynchronous
Python apps
. ASGI phù hợp với tất cả ứng dụng sử dụng WSGI do có cơ chế tương thích ngược.
Ok dông dài đủ rồi, chúng ta tiếp tục tìm hiểu xem FastAPI còn cung cấp những tiện ích gì nhé.
FastAPI Docs
Do based trên OpenAI mà trước đó có tên là Swagger nên FastAPI cung cấp doc có giao diện dễ nhìn, dễ sử dụng. Ví dụ minh họa:
Khi bật doc bằng local url http://0.0.0.0:8000/docs
.
1 giao diện khác của FastAPI docs http://0.0.0.0:8000/redoc
.
Performance
Các bạn có thể test hiệu năng của các web framework trên trang này (https://www.techempower.com/benchmarks/)
Optional Depencies
Do FastAPI based trên Pydantic và Starlette nên có hỗ trợ thêm 1 số thư viện có cũng được không có cũng không sao:
Pydantic:
ujson
: JSON “parsing” nhanh hơn.email_validator
: validate email.
Starlette:
requests
: khi bạn muốn tạo request, dùngTestClient
.aiofiles
: khi bạn muốn dùngFileResponse
hoặcStaticFile
.jinja2
: nếu bạn muốn dùng các mẫu config mặc định.python-multipart
: hỗ trợ “parsing” với request.form().itsdangerous
: hỗ trợSessionMiddleware
.graphene
: hỗ trợGraphQL
.
FastAPI:
uvicorn
: ASGI server phục vụ cho ứng dụng của bạn.orjson
: nếu muốn dùngORJSONResponse
.
Nếu muốn dùng hết thư viện trên thì bạn chỉ cần dùng 1 câu lệnh đơn giản.
1 2 | pip install fastapi[all] |
Hướng dẫn cơ bản
Create a simple API
Về cơ bản thì code dễ như ăn kẹo, bạn tạo 1 file main.py
.
1 2 3 4 5 6 7 8 9 | <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI <span class="token comment">#import class FastAPI() từ thư viện fastapi</span> app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># gọi constructor và gán vào biến app</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">)</span> <span class="token comment"># giống flask, khai báo phương thức get và url</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">root</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># do dùng ASGI nên ở đây thêm async, nếu bên thứ 3 không hỗ trợ thì bỏ async đi</span> <span class="token keyword">return</span> <span class="token punctuation">{</span><span class="token string">"message"</span><span class="token punctuation">:</span> <span class="token string">"Hello World"</span><span class="token punctuation">}</span> |
Sau đó chạy dòng code này để chạy app
1 2 | uvicorn main:app --host 0.0.0.0 --port 8000 |
P/S: nếu bạn làm trong môi trường phát triển có thể thêm --reload
để tự động restart sau khi thay đổi code.
Tiếp sau đó vào xem thử thành quả phát http://127.0.0.1:8000/docs
.
Ấn vào Try it out
-> Execute
-> API trả về response.
Giao diện API này được thiết kế dựa trên OpenAPI. Bên đó có hẳn 1 khái niệm để define API gọi là “Schema”. Nếu bạn tò mò thì vào link này http://127.0.0.1:8000/openapi.json
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <span class="token punctuation">{</span> <span class="token property">"openapi"</span><span class="token operator">:</span> <span class="token string">"3.0.2"</span><span class="token punctuation">,</span> <span class="token property">"info"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"FastAPI"</span><span class="token punctuation">,</span> <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"0.1.0"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"paths"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"/"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"get"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"summary"</span><span class="token operator">:</span> <span class="token string">"Root"</span><span class="token punctuation">,</span> <span class="token property">"operationId"</span><span class="token operator">:</span> <span class="token string">"root__get"</span><span class="token punctuation">,</span> <span class="token property">"responses"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Successful Response"</span><span class="token punctuation">,</span> <span class="token property">"content"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"application/json"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"schema"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Nói chung bạn chỉ cần 6 bước để tạo 1 API
- Bước 1: import fastapi
- Bước 2: tạo 1 instance của class FastAPI
- Bước 3: tạo đường dẫn, bắt đầu từ
/
- Bước 4: khai báo phương thức HTTP: post, get, put, delete hay options, head, patch, trace
- Bước 5: khai báo hàm
- Bước 6: trả về content với format dict, list, str, int, …
Path Parameters
Bạn có thể truyền param thông qua đường dẫn.
1 2 3 4 5 6 7 8 9 | <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/items/{item_id}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_item</span><span class="token punctuation">(</span>item_id<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">}</span> |
Biến item_id
trên đường dẫn sẽ truyền vào hàm read_item với thông qua param trùng tên item_id
. Test thử http://127.0.0.1:8000/items/foo
.
Path parameters with types
Bạn cũng có thể khai báo định dạng của param để trả về khi truyền biến đúng định dạng sẽ trả về giá trị.
1 2 3 4 5 6 7 8 9 | <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/items/{item_id}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_item</span><span class="token punctuation">(</span>item_id<span class="token punctuation">:</span> <span class="token builtin">int</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">}</span> |
Data validation
Còn nếu không đúng định dạng thì trả về thông báo. Mọi dữ liệu được validate đều dựa trên Pydantic.
Order
Nếu bạn có khai báo đường dẫn trùng lặp như thế này:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/users/me"</span><span class="token punctuation">)</span> <span class="token comment"># <- here</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_user_me</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{</span><span class="token string">"user_id"</span><span class="token punctuation">:</span> <span class="token string">"the current user"</span><span class="token punctuation">}</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/users/{user_id}"</span><span class="token punctuation">)</span> <span class="token comment"># <- and here</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_user</span><span class="token punctuation">(</span>user_id<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{</span><span class="token string">"user_id"</span><span class="token punctuation">:</span> user_id<span class="token punctuation">}</span> |
Thì nhớ để theo thứ tự /users/me
trước rồi đến /users/{user_id}
sau, ngược lại nếu /users/{user_id}
ở trước thì sẽ nghĩ rằng “user_id” được nhận giá trị me
.
Path in path
FastAPI hỗ trợ khai báo đường dẫn trong đường dẫn API nhờ vào việc based Starlette.
1 2 3 4 | /files/{file_path} file_path = /home/johndoe/myfile.txt => /files/home/johndoe/myfile.txt |
1 2 3 4 5 6 7 8 9 | <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/files/{file_path:path}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_file</span><span class="token punctuation">(</span>file_path<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{</span><span class="token string">"file_path"</span><span class="token punctuation">:</span> file_path<span class="token punctuation">}</span> |
Query Parameters
Nếu bạn truyền param dưới dạng key-value thì ở trong FastAPI có hỗ trợ với tên gọi “query” parameters.
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> fake_items_db <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">{</span><span class="token string">"item_name"</span><span class="token punctuation">:</span> <span class="token string">"Foo"</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token string">"item_name"</span><span class="token punctuation">:</span> <span class="token string">"Bar"</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token string">"item_name"</span><span class="token punctuation">:</span> <span class="token string">"Baz"</span><span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token comment"># pair format: key-value</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/items/"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_item</span><span class="token punctuation">(</span>skip<span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> limit<span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">return</span> fake_items_db<span class="token punctuation">[</span>skip <span class="token punctuation">:</span> skip <span class="token operator">+</span> limit<span class="token punctuation">]</span> <span class="token comment"># trả về dữ liệu từ skip đến skip + limit</span> |
Kiểm tra ở link http://127.0.0.1:8000/items/?skip=0&limit=10
:
Nếu bạn để ý skip và limit có format string khi làm đường dẫn nhưng một khi truyền về hàm thì sẽ ngay lập tức được convert từ string về int.
Optional parameters
Ngoài ra FastAPI cung cấp một cách khai báo optional
query parameters, mặc định là None.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/items/{item_id}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_item</span><span class="token punctuation">(</span>item_id<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">,</span> q<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token triple-quoted-string string">''' param item_id: format string param q: format string, default value: None, Optional: help you find error that happen '''</span> <span class="token keyword">if</span> q<span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">,</span> <span class="token string">"q"</span><span class="token punctuation">:</span> q<span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">}</span> |
Như bạn thấy ở trên param truyền ở đường dẫn là item_id
, nhưng trong hàm có thêm param q
. FastAPI chỉ sử dụng str
để nhận định format của param còn Optional
thì FastAPI không sử dụng, chỉ có tác dụng check lỗi nếu xảy ra.
Bạn có thể test bằng đường dẫn sau.
1 2 | http://127.0.0.1:8000/items/1?q=1 # 1 là item_id và ?q=1 là giá trị của q |
Query parameter type conversion
Thay đổi giá trị mặc định bằng cách truyền giá trị trên đường dẫn.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/items/{item_id}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_item</span><span class="token punctuation">(</span>item_id<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">,</span> short<span class="token punctuation">:</span> <span class="token builtin">bool</span> <span class="token operator">=</span> <span class="token boolean">False</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># param short với định dạng boolean có giá trị mặc định là False</span> item <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token keyword">not</span> short<span class="token punctuation">:</span> item<span class="token punctuation">.</span>update<span class="token punctuation">(</span> <span class="token punctuation">{</span><span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">"This is an amazing item that has a long description"</span><span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> item |
Trong trường hợp này
1 2 3 4 | http://127.0.0.1:8000/items/foo?short=1 or http://127.0.0.1:8000/items/foo?short=True |
Multiple path and query parameters
Với các đường dẫn lồng nhau, FastAPI biết param nào với param nào dựa trên tên param.
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/users/{user_id}/items/{item_id}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_user_item</span><span class="token punctuation">(</span>user_id<span class="token punctuation">:</span> <span class="token builtin">int</span><span class="token punctuation">,</span> item_id<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">)</span><span class="token punctuation">:</span> item <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">,</span> <span class="token string">"owner_id"</span><span class="token punctuation">:</span> user_id<span class="token punctuation">}</span> <span class="token keyword">return</span> item |
Required query parameters
Đơn giản là bạn điền thiếu param trên đường dẫn sẽ báo lỗi
1 2 3 4 5 6 7 8 9 10 | from fastapi import FastAPI app = FastAPI() @app.get("/items/{item_id}") async def read_user_item(item_id: str, needy: str): item = {"item_id": item_id, "needy": needy} return item |
Như hình dưới này, tôi chỉ truyền vào giá trị của item_id
còn giá trị của needy
thì không nên sinh ra lỗi.
Request Body
- Request body: người dùng gửi request từ browser đến API.
- Response body: dựa trên request, APi trả về response cho người dùng.
Để khai báo format của request body, bạn cần sử dụng Pydantic
models.
P/S: nhắc nhở khi send request cần sử dụng phương thức POST, nếu dùng phương thức GET thì bạn sẽ bị lộ thông tin trên URL => tính bảo mật không cao.
Pydantic Models
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI <span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel <span class="token comment"># import class BaseModel của thư viện pydantic</span> <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># kế thừa từ class Basemodel và khai báo các biến</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>post</span><span class="token punctuation">(</span><span class="token string">"/items/"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">create_item</span><span class="token punctuation">(</span>item<span class="token punctuation">:</span> Item<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># khai báo dưới dạng parameter</span> <span class="token keyword">return</span> item |
Ví dụ về 1 instance của class Item.
1 2 3 4 5 6 7 | { "name": "Foo", "description": "An optional description", "price": 45.2, "tax": 3.5 } |
Do description
và tax
có giá trị None nên bạn có thể không cần thêm vào cũng được.
1 2 3 4 5 | { "name": "Foo", "price": 45.2 } |
Dựa trên việc import Pydantic module, FastAPI hỗ trợ:
- Đọc request body dưới dạng Json.
- Chuyển đổi định dạng biến.
- Validate dữ liệu
- Khai báo format mặc định của request body, class Item trên là 1 ví dụ.
- Gen JSON Schema cho model của bạn
- Schema sẽ được gen thành UI của OpenAI doc.
Use model
Trong hàm create_item, bạn có thể tùy biến các biến của class Item, đơn giản như việc tính phí chịu thuế bằng cách tính tổng item.price
và item.tax
như bên dưới.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI <span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>post</span><span class="token punctuation">(</span><span class="token string">"/items/"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">create_item</span><span class="token punctuation">(</span>item<span class="token punctuation">:</span> Item<span class="token punctuation">)</span><span class="token punctuation">:</span> item_dict <span class="token operator">=</span> item<span class="token punctuation">.</span><span class="token builtin">dict</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">if</span> item<span class="token punctuation">.</span>tax<span class="token punctuation">:</span> price_with_tax <span class="token operator">=</span> item<span class="token punctuation">.</span>price <span class="token operator">+</span> item<span class="token punctuation">.</span>tax item_dict<span class="token punctuation">.</span>update<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"price_with_tax"</span><span class="token punctuation">:</span> price_with_tax<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">return</span> item_dict |
Request body + path parameters
FastAPI hỗ trợ khai báo tham số URL và request body cùng lúc, framework sẽ biết tham số nào truyền từ đường dẫn và tham số nào lấy từ request.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI <span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>put</span><span class="token punctuation">(</span><span class="token string">"/items/{item_id}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">create_item</span><span class="token punctuation">(</span>item_id<span class="token punctuation">:</span> <span class="token builtin">int</span><span class="token punctuation">,</span> item<span class="token punctuation">:</span> Item<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">,</span> <span class="token operator">**</span>item<span class="token punctuation">.</span><span class="token builtin">dict</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span> |
P/S: tương tự như trên bạn có thể thêm tham số URL, tham số query và request body cùng lúc.
Query Parameters and String Validations
Ở phần trước chúng ta đã biết khái niệm của query parameter rồi, lạ 1 loại param có cũng được không có cũng không sao. Param này có attribute là Optional
, nhưng độ dài bị giới hạn không vượt quá 50 ký tự. Nên FastAPI cung cấp class Query.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from typing import Optional from fastapi import FastAPI, Query app = FastAPI() @app.get("/items/") async def read_items(q: Optional[str] = Query(None, max_length=50)): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) return results |
Câu lệnh q: Optional[str] = Query(None)
cũng tương tự q: Optional[str] = None
nhưng Query cung cấp các param khác như max_lenght, min_lenght, regex, … Bạn có thể tăng giới hạn ký tự thành 250 như thế này chỉ việc thay đổi giá trị tham số. (Mặc định của max_lenght là 50)
1 2 | q: Optional[str] = Query(None, max_length=250) |
Query parameter list / multiple values
Ngoài định dạng string và integer, FastAPI còn hỗ trợ type List.
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> List<span class="token punctuation">,</span> Optional <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI<span class="token punctuation">,</span> Query app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/items/"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_items</span><span class="token punctuation">(</span>q<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span>List<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> Query<span class="token punctuation">(</span><span class="token boolean">None</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> query_items <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"q"</span><span class="token punctuation">:</span> q<span class="token punctuation">}</span> <span class="token keyword">return</span> query_items |
1 2 3 | # q là 1 List có thể chứa nhiều giá trị. http://localhost:8000/items/?q=foo&q=bar |
Response body mà API trả về.
1 2 3 4 5 6 7 | { "q": [ "foo", "bar" ] } |
API cũng được cập nhật theo.
P/S: bạn cũng có thể thay List[str]
thành list
như thế này.
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI<span class="token punctuation">,</span> Query app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/items/"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_items</span><span class="token punctuation">(</span>q<span class="token punctuation">:</span> <span class="token builtin">list</span> <span class="token operator">=</span> Query<span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> query_items <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"q"</span><span class="token punctuation">:</span> q<span class="token punctuation">}</span> <span class="token keyword">return</span> query_items |
Query còn 1 vài param nữa nhưng không quá quan trọng, bạn có thể vào doc của FastAPI để tìm hiểu chi tiết.
Các param mà Query cung cấp:
Metadata
alias
: tên khác của paramtitle
: metadata đặt tên paramdescription
: metadata giới thiệu paramdeprecated
: khi bạn chán param nào thì thêm vào để người dùng biết là bạn không còn sử dụng param đó nữa
Validation cho string:
min_lenght
max_lenght
regex
Path Parameters and Numeric Validations
Query parameters có class Query để khai báo metadata và validations, Path parameters có class Pass với cơ chế tương tự.
Thêm title
metadata cho path param item_id
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI<span class="token punctuation">,</span> Path<span class="token punctuation">,</span> Query app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/items/{item_id}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_items</span><span class="token punctuation">(</span> item_id<span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token operator">=</span> Path<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> title<span class="token operator">=</span><span class="token string">"The ID of the item to get"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> q<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> Query<span class="token punctuation">(</span><span class="token boolean">None</span><span class="token punctuation">,</span> alias<span class="token operator">=</span><span class="token string">"item-query"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">)</span><span class="token punctuation">:</span> results <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">}</span> <span class="token keyword">if</span> q<span class="token punctuation">:</span> results<span class="token punctuation">.</span>update<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"q"</span><span class="token punctuation">:</span> q<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">return</span> results |
Number validations: greater than or equal
Chúng ta không chỉ có thể validate string mà còn validate được number.
Với param ge=1
của class Path, item_id
bắt buộc phải là 1 số lớn hơn hoặc bằng 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI<span class="token punctuation">,</span> Path app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/items/{item_id}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">read_items</span><span class="token punctuation">(</span> <span class="token operator">*</span><span class="token punctuation">,</span> item_id<span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token operator">=</span> Path<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> title<span class="token operator">=</span><span class="token string">"The ID of the item to get"</span><span class="token punctuation">,</span> ge<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> q<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token punctuation">)</span><span class="token punctuation">:</span> results <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">}</span> <span class="token keyword">if</span> q<span class="token punctuation">:</span> results<span class="token punctuation">.</span>update<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"q"</span><span class="token punctuation">:</span> q<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">return</span> results |
Number validations: greater than and less than or equal
Tương tự với le=100
, item_id
bắt buộc phải là 1 số nhỏ hơn hoặc bằng 100.
1 2 | item_id: int = Path(..., title="The ID of the item to get", gt=0, le=1000) |
P/S: Number validations không chỉ hỗ trợ type integer mà còn hỗ trợ cho type float.
1 2 | size: float = Query(..., gt=0, lt=10.5) |
gt
: >gt>ge
: ≥ge≥lt
: <lt<le
: ≤le≤
Body
Multiple Parameters
Đơn giản là FastAPI hỗ trợ tạo format cho request body, bạn có thể dùng không chỉ 1 mà là N Pydantic model như ví dụ dưới, tôi khai báo 2 class Item
và User
tương ứng 2 Pydantic model.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI <span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> <span class="token keyword">class</span> <span class="token class-name">User</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> username<span class="token punctuation">:</span> <span class="token builtin">str</span> full_name<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>put</span><span class="token punctuation">(</span><span class="token string">"/items/{item_id}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">update_item</span><span class="token punctuation">(</span>item_id<span class="token punctuation">:</span> <span class="token builtin">int</span><span class="token punctuation">,</span> item<span class="token punctuation">:</span> Item<span class="token punctuation">,</span> user<span class="token punctuation">:</span> User<span class="token punctuation">)</span><span class="token punctuation">:</span> results <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">,</span> <span class="token string">"item"</span><span class="token punctuation">:</span> item<span class="token punctuation">,</span> <span class="token string">"user"</span><span class="token punctuation">:</span> user<span class="token punctuation">}</span> <span class="token keyword">return</span> results |
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token punctuation">{</span> <span class="token string">"item"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"Foo"</span><span class="token punctuation">,</span> <span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">"The pretender"</span><span class="token punctuation">,</span> <span class="token string">"price"</span><span class="token punctuation">:</span> <span class="token number">42.0</span><span class="token punctuation">,</span> <span class="token string">"tax"</span><span class="token punctuation">:</span> <span class="token number">3.2</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"user"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"username"</span><span class="token punctuation">:</span> <span class="token string">"Hoang"</span><span class="token punctuation">,</span> <span class="token string">"full_name"</span><span class="token punctuation">:</span> <span class="token string">"Hoang Pham"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Singular values in body
Bạn cũng có thể thêm define 1 body cho chỉ 1 giá trị mà không cần khai báo class, giả dụ ở đây tôi thêm 1 param là importance
có type là int và cũng là 1 key nằm trong json body, nên khi post data thì bạn cũng phải khai báo giá trị cho importance
.
1 2 3 4 | <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">update_item</span><span class="token punctuation">(</span> item_id<span class="token punctuation">:</span> <span class="token builtin">int</span><span class="token punctuation">,</span> item<span class="token punctuation">:</span> Item<span class="token punctuation">,</span> user<span class="token punctuation">:</span> User<span class="token punctuation">,</span> importance<span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token operator">=</span> Body<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">:</span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token punctuation">{</span> <span class="token string">"item"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"Foo"</span><span class="token punctuation">,</span> <span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">"The pretender"</span><span class="token punctuation">,</span> <span class="token string">"price"</span><span class="token punctuation">:</span> <span class="token number">42.0</span><span class="token punctuation">,</span> <span class="token string">"tax"</span><span class="token punctuation">:</span> <span class="token number">3.2</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"user"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"username"</span><span class="token punctuation">:</span> <span class="token string">"Hoang"</span><span class="token punctuation">,</span> <span class="token string">"full_name"</span><span class="token punctuation">:</span> <span class="token string">"Hoang Pham"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"importance"</span><span class="token punctuation">:</span> <span class="token number">5</span> <span class="token punctuation">}</span> |
Multiple body params and query
Nói đơn giản là kết hợp multiple body param với query param.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">update_item</span><span class="token punctuation">(</span> <span class="token operator">*</span><span class="token punctuation">,</span> item_id<span class="token punctuation">:</span> <span class="token builtin">int</span><span class="token punctuation">,</span> item<span class="token punctuation">:</span> Item<span class="token punctuation">,</span> user<span class="token punctuation">:</span> User<span class="token punctuation">,</span> importance<span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token operator">=</span> Body<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> gt<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> q<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> <span class="token punctuation">)</span><span class="token punctuation">:</span> results <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">,</span> <span class="token string">"item"</span><span class="token punctuation">:</span> item<span class="token punctuation">,</span> <span class="token string">"user"</span><span class="token punctuation">:</span> user<span class="token punctuation">,</span> <span class="token string">"importance"</span><span class="token punctuation">:</span> importance<span class="token punctuation">}</span> <span class="token keyword">if</span> q<span class="token punctuation">:</span> results<span class="token punctuation">.</span>update<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"q"</span><span class="token punctuation">:</span> q<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">return</span> results |
Field
Để validate data hoặc thêm metadata trong 1 class giả dụ Item
chẳng hạn, bạn cần import Field
operation function từ module pydantic
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> Body<span class="token punctuation">,</span> FastAPI <span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel<span class="token punctuation">,</span> Field app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> Field<span class="token punctuation">(</span> <span class="token boolean">None</span><span class="token punctuation">,</span> title<span class="token operator">=</span><span class="token string">"The description of the item"</span><span class="token punctuation">,</span> max_length<span class="token operator">=</span><span class="token number">300</span> <span class="token punctuation">)</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> <span class="token operator">=</span> Field<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> gt<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">"The price must be greater than zero"</span><span class="token punctuation">)</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>put</span><span class="token punctuation">(</span><span class="token string">"/items/{item_id}"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">update_item</span><span class="token punctuation">(</span>item_id<span class="token punctuation">:</span> <span class="token builtin">int</span><span class="token punctuation">,</span> item<span class="token punctuation">:</span> Item <span class="token operator">=</span> Body<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> embed<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> results <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"item_id"</span><span class="token punctuation">:</span> item_id<span class="token punctuation">,</span> <span class="token string">"item"</span><span class="token punctuation">:</span> item<span class="token punctuation">}</span> <span class="token keyword">return</span> results |
Như đoạn code ở trên param description
có metadata là title, với length không vượt quá 300 từ, hay như param price
không được nhỏ hơn 0 và có metadata là description.
Nested Models
Ngoài các kiểu int, float, str, bạn còn có thể thêm kiểu list hay set như dưới đây.
1 2 3 4 5 6 7 | <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> tags<span class="token punctuation">:</span> <span class="token builtin">list</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> |
Với cách khai báo trên, khi post bạn truyền param là 1 list, nhưng với cách khai báo trên thì list này sẽ không xác định kiểu định dạng của từng phần tử trong list.
Không sao bởi Python có module List
hỗ trợ bạn khai báo param là list xác định kiểu định dạng của từng phần tử.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> List<span class="token punctuation">,</span> Optional <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI <span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> tags<span class="token punctuation">:</span> List<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> |
Tương tự với List
, bạn có thể thêm Set
.
1 2 3 4 5 6 7 8 9 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional<span class="token punctuation">,</span> Set <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> tags<span class="token punctuation">:</span> Set<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token builtin">set</span><span class="token punctuation">(</span><span class="token punctuation">)</span> |
Ngoài ra các kiểu normal như str, int, float, … FastAPI cũng hỗ trợ thêm các định dạng phức tạp và đa dạng hơn, giả sử định dạng HttpUrl
kế thừa từ định dạng str
. Để biết thêm chi tiết mời check link này (https://pydantic-docs.helpmanual.io/usage/types/).
- Tiếp sau đây tôi sẽ giới thiệu các bạn cách khai báo 1 model lồng trong 1 model khác như thế nào.
Giả sử tôi có 2 class Images và Item.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional<span class="token punctuation">,</span> Set <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI <span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">class</span> <span class="token class-name">Image</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> url<span class="token punctuation">:</span> <span class="token builtin">str</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> tags<span class="token punctuation">:</span> Set<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> |
Tôi muốn class Images nằm trong class Item như thế này.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token punctuation">{</span> <span class="token string">"item"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"Foo"</span><span class="token punctuation">,</span> <span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">"The pretender"</span><span class="token punctuation">,</span> <span class="token string">"price"</span><span class="token punctuation">:</span> <span class="token number">42.0</span><span class="token punctuation">,</span> <span class="token string">"tax"</span><span class="token punctuation">:</span> <span class="token number">3.2</span><span class="token punctuation">,</span> <span class="token string">"tags"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"rock"</span><span class="token punctuation">,</span> <span class="token string">"metal"</span><span class="token punctuation">,</span> <span class="token string">"bar"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"image"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"url"</span><span class="token punctuation">:</span> <span class="token string">"http://example.com/baz.jpg"</span><span class="token punctuation">,</span> <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"The Foo live"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Bạn chỉ cần thêm 1 dòng code vào class Item. Easy !
1 2 3 4 5 6 7 8 | <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> tags<span class="token punctuation">:</span> Set<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> image<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span>Image<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> |
Bạn cũng có thể tùy biến định dạng của Pydantic models là list hoặc set chẳng hạn.
1 2 | images<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span>List<span class="token punctuation">[</span>Image<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> |
Và đây là kết quả.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token punctuation">{</span> <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"Foo"</span><span class="token punctuation">,</span> <span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">"The pretender"</span><span class="token punctuation">,</span> <span class="token string">"price"</span><span class="token punctuation">:</span> <span class="token number">42.0</span><span class="token punctuation">,</span> <span class="token string">"tax"</span><span class="token punctuation">:</span> <span class="token number">3.2</span><span class="token punctuation">,</span> <span class="token string">"tags"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">"rock"</span><span class="token punctuation">,</span> <span class="token string">"metal"</span><span class="token punctuation">,</span> <span class="token string">"bar"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"images"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token string">"url"</span><span class="token punctuation">:</span> <span class="token string">"http://example.com/baz.jpg"</span><span class="token punctuation">,</span> <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"The Foo live"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"url"</span><span class="token punctuation">:</span> <span class="token string">"http://example.com/dave.jpg"</span><span class="token punctuation">,</span> <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"The Baz"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> |
Trên lý thuyết bạn có thể lặp đi lặp lại các models lồng nhau như sau. Class Image nằm trong class Item, class Item thì lại nằm trong class Offer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> List<span class="token punctuation">,</span> Optional<span class="token punctuation">,</span> Set <span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI<span class="token punctuation">,</span> Body <span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel<span class="token punctuation">,</span> HttpUrl app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">class</span> <span class="token class-name">Image</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> url<span class="token punctuation">:</span> HttpUrl name<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token keyword">class</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> tax<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">float</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> tags<span class="token punctuation">:</span> Set<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> images<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span>List<span class="token punctuation">[</span>Image<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> <span class="token keyword">class</span> <span class="token class-name">Offer</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span> name<span class="token punctuation">:</span> <span class="token builtin">str</span> description<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> price<span class="token punctuation">:</span> <span class="token builtin">float</span> items<span class="token punctuation">:</span> List<span class="token punctuation">[</span>Item<span class="token punctuation">]</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>post</span><span class="token punctuation">(</span><span class="token string">"/offers/"</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">create_offer</span><span class="token punctuation">(</span>offer<span class="token punctuation">:</span> Offer <span class="token operator">=</span> Body<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> embed<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">return</span> offer |
Kết luận
Do FastAPI là 1 framework API mới, có rất nhiều tính năng nên tôi chia ra thành nhiều phần (căn bản do không đủ kiên nhẫn để viết). Ở đây tôi sẽ chỉ liệt kê các tính năng quan trọng dùng nhiều trước rồi sau đó sẽ nâng cao lên trong các phần tiếp theo. Bạn cũng có thể xem thẳng trên doc của fastapi. Link tham khảo here: