🤩Hello World! - Làm quen với Flask-RESTful
Chương trình API đơn giản
Đoạn mã nguồn tạo một ứng dụng RESTful đơn giản với địa chỉ /
để trả về một đối tượng JSON có với key là hello
và value là world
.
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
return {'hello': 'world'}
api.add_resource(HelloWorld, '/')
if __name__ == '__main__':
app.run(debug=True)
🤖 Giải thích đoạn chương trình:
Đoạn mã nguồn bắt đầu bằng câu lệnh
from flask import Flask
, để import thư viện Flask.Tiếp theo, câu lệnh
from flask_restful import Resource, Api
để import thư viện Flask-RESTful, để tạo ra một ứng dụng web RESTful.Câu lệnh
app = Flask(__name__)
tạo một đối tượng ứng dụng Flask, với tên ứng dụng là__name__
, để chỉ định tên ứng dụng.Câu lệnh
api = Api(app)
tạo một đối tượng API, với ứng dụng Flask làapp
.Class
HelloWorld
được định nghĩa bên trongapi
và kế thừa từResource
. Phương thứcget
trong classHelloWorld
sẽ được gọi khi có yêu cầuGET
đến địa chỉ/
(địa chỉ Web cấp Root). Phương thứcget
này trả về một đối tượng JSON có key làhello
và value làworld
.Câu lệnh
api.add_resource(HelloWorld, '/')
thêm classHelloWorld
vào API, với địa chỉ/
(địa chỉ Web cấp Root).Cuối cùng, câu lệnh
if __name__ == '__main__':
chỉ định rằng đây là một ứng dụng chính, và sẽ được thực thi khi ứng dụng được khởi chạy. Câu lệnhapp.run(debug=True)
chạy ứng dụng với môi trường debug. Cần lưu ý rằng tính năng debug chỉ nên kích hoạt trong quá trình lập trình, và nên tắt trong quá trình triển khai sử dụng thực tế.
Để thực thi đoạn chương trình trên, trước hết, cần lưu lại thành tập tin và đặt tên api.py, sau đó thực thi lệnh $ python api.py
trong môi trường CMD hoặc Terminal. Lưu ý, cần kích hoạt môi trường lập trình trước khi thực thi lệnh trên.
$ python api.py
* Serving Flask app 'api'
* Debug mode: on
* Running on http://127.0.0.1:5000
Tương tác với API bằng cách thực thi đoạn mã $ curl http://127.0.0.1:5000/
trong một cửa sổ CMD hoặc Terminal mới, kết quả trả về là một đối tượng JSON.
$ curl http://127.0.0.1:5000/
{
"Hello": "World"
}
Định tuyến tài nguyên
Trong đoạn chương trình Python trên, chúng ta thấy rằng API của lớp HelloWorld
có thể được truy cập từ vị trí /
(địa chỉ Web cấp Root). Trong phần này, bài hướng dẫn sẽ trình bày cách định tuyến ở mức chi tiết hơn, cũng như cách khai thác các phương thức HTTP như GET, PUT.
Đoạn chương trình bên dưới định nghĩa một lớp SimpleTodo
, bao gồm hai phương thức là get
và put
. Trong đó, phương thức get sẽ truy xuất dữ liệu trong danh sách todos
(cấu trúc dữ liệu dict
) theo khóa (key) là todo_id
. Phương thức put sẽ thực hiện lấy dữ liệu từ request.form['data']
và ghi vào danh sách todos
.
from flask import Flask, request
from flask_restful import Api, Resource
# Define app configurations
app = Flask(__name__)
api = Api(app)
# Example 2
todos = {}
class SimpleTodo(Resource):
def get(self, todo_id):
item = todos.get(todo_id)
if item is not None:
return {todo_id: item}
return {todo_id: 'todo_id is not found!'}
def put(self, todo_id):
data = request.form['data']
if data is not None:
todos[todo_id] = data
return {todo_id: todos[todo_id]}
return {'msg': 'An Unexpected Error Occurred!'}
# Example 1
class HelloWorld(Resource):
def get(self):
return {'Hello': 'World'}
# Define URI
api.add_resource(HelloWorld, '/')
api.add_resource(SimpleTodo, '/todo/<string:todo_id>')
if __name__ == '__main__':
app.run(debug=True)
Đoạn chương trình trên có thể được tương tác thông qua các câu lệnh sau trên môi trường CMD hoặc Terminal.
$ curl http://127.0.0.1:5000/todo/todo1 -d "data=Remember to do homework" -X PUT
{"todo1": "Remember to do homework"}
$ curl http://127.0.0.1:5000/todo1
{"todo1": "Remember to do homework"}
$ curl http://127.0.0.1:5000/todo/todo2
{"todo2": "todo_id is not found!"}
Với mỗi lệnh thực thi ở trên, hãy xem những kết quả trả về tương ứng trong cửa sổ CMD hoặc Terminal khởi chạy chương trình, và để ý phương thức HTTP ở dòng 1 và 2 dưới đây.
127.0.0.1 - - [30/Nov/2023 15:08:37] "PUT /todo/todo1 HTTP/1.1" 200 -
127.0.0.1 - - [30/Nov/2023 15:08:41] "GET /todo/todo1 HTTP/1.1" 200 -
127.0.0.1 - - [30/Nov/2023 15:08:45] "GET /todo/todo2 HTTP/1.1" 200 -
Flask-RESTful còn cho phép phản hồi (response) một cách tường minh các mã trạng thái HTTP, chẳng hạn, 200 OK
hay 201 Created
.
class Todo1(Resource):
def get(self):
# Default is 200 OK
return {'Hello': 'world'}
class Todo2(Resource):
def get(self):
# Set the response code to 201
return {'Hello': 'world'}, 201
class Todo3(Resource):
def get(self):
# Set the response code to 201 and return custom headers
return {'Hello': 'world'}, 201, {'test-header': 'enter-text-here'}
Để xem được giá trị "custom headers", như trình bày trong lớp Todo3
, chúng ta có thể sử dụng phần mềm Postman, kết quả được thể hiện như trong hình bên dưới.

Endpoints
Trong bài hướng dẫn này, cũng như trong lĩnh vực lập trình Microservices, thuật ngữ Endpoint thường được sử dụng nguyên mẫu tiếng Anh. Để hiểu về khái niệm này, trợ lý AI sẽ trình bày bằng cả tiếng Việt và tiếng Anh.
Flask-RESRful cho phép lập trình khai báo nhiều Endpoints cho cùng một tài nguyên (resource). Cụ thể, lập trình viên chỉ cần truyền thêm các URL vào phương thức add_resource()
của đối tượng Api
.
api.add_resource(SimpleTodo,
'/todo/<string:todo_id>',
'/todo/')
Trong đoạn mã trên, được mở rộng từ chương trình minh họa, chúng ta thấy ưu điểm quan trọng của việc khai báo nhiều Endpoint cho cùng một Resource. Cụ thể, trong trường hợp yêu cầu (request) không bao gồm tham số <string:todo_id>
, thì chương trình sẽ sử dụng Endpoint tiếp theo, /todo/
trong tình huống này.
Xử lý tham số đầu vào
Flask-RESTful được bao gồm sẵn cơ chế hỗ trợ lập trình xử lý tham số đầu vào (argument parsing) cho các API Endpoint.
from flask_restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('rate', type=int, help='Rate to charge for this resource')
args = parser.parse_args()
🤖 Đoạn mã parser.parse_args()
sẽ trả về một đối tượng chứa các đối số được truyền vào trong mỗi request
. Trong trường hợp này, nó sẽ trả về một đối tượng chứa đối số rate
được truyền vào trong request
và có kiểu dữ liệu là số nguyên (int
).
Khi sử dụng module reqparse
của Flask-RESTful, trình biên dịch sẽ trả về mã lỗi dựa trên bộ mã trạng thái HTTP và được biểu diễn theo định dạng JSON.
$ curl -d 'rate=foo' http://127.0.0.1:5000/SimpleTodo
{'status': 400, 'message': 'foo cannot be converted to int'}
Định dạng dữ liệu
Bên cạnh hỗ trợ thao tác trên các cấu trúc dữ liệu của Python, Flask-RESTful hỗ trợ thao tác trên kiểu dữ liệu đối tượng, thông qua module fields
và decorator (tạm dịch: tiền chỉ thị) marshal_with()
.
from flask_restful import fields, marshal_with
resource_fields = {
'task': fields.String,
'uri': fields.Url('todo_ep')
}
class TodoDao(object):
def __init__(self, todo_id, task):
self.todo_id = todo_id
self.task = task
# This field will not be sent in the response
self.status = 'active'
class Todo(Resource):
@marshal_with(resource_fields)
def get(self, **kwargs):
return TodoDao(todo_id='my_todo', task='Remember the milk')
Trong đoạn chương trình trên, decorator marshal_with()
sẽ áp dụng quá trình biến đổi được mô tả bởi resource_fields
. Trong đó, chỉ có thuộc tính task
được trích xuất từ đối tượng ban đầu, còn thuộc tính todo_id
bị bỏ qua, theo như định nghĩa trong resource_fields
. Trường fields.Url
là một trường đặc biệt nhận đầu vào là tên của Endpoint và tạo ra một URL tương ứng trong phản hồi.
Chương trình "Hello World!"
Trong phần này, bài hướng dẫn sẽ giới thiệu một chương trình hoàn chỉnh được lập trình trên Flask-RESTful. Đoạn chương trình được lưu trong tập tin có tên api.py.
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
app = Flask(__name__)
api = Api(app)
TODOS = {
'todo1': {'task': 'Getting started with Flask-RESTful'},
'todo2': {'task': 'Program an use-case'},
'todo3': {'task': 'Improve the program'},
}
def abort_if_todo_doesnt_exist(todo_id):
if todo_id not in TODOS:
abort(404, message="Todo {} doesn't exist".format(todo_id))
parser = reqparse.RequestParser()
parser.add_argument('task')
# Todo
# shows a single todo item and lets you delete a todo item
class Todo(Resource):
def get(self, todo_id):
abort_if_todo_doesnt_exist(todo_id)
return TODOS[todo_id]
def delete(self, todo_id):
abort_if_todo_doesnt_exist(todo_id)
del TODOS[todo_id]
return '', 204
def put(self, todo_id):
args = parser.parse_args()
task = {'task': args['task']}
TODOS[todo_id] = task
return task, 201
# TodoList
# shows a list of all todos, and lets you POST to add new tasks
class TodoList(Resource):
def get(self):
return TODOS
def post(self):
args = parser.parse_args()
todo_id = int(max(TODOS.keys()).lstrip('todo')) + 1
todo_id = 'todo%i' % todo_id
TODOS[todo_id] = {'task': args['task']}
return TODOS[todo_id], 201
## Setup the Api resource routing here
api.add_resource(TodoList, '/todos')
api.add_resource(Todo, '/todos/<todo_id>')
if __name__ == '__main__':
app.run(debug=True)
🤖 Chương trình trên sử dụng Flask-RESTful để tạo một API cho việc quản lý các công việc (todos). Đây là một ví dụ cơ bản về cách tạo các endpoint để thực hiện các thao tác CRUD (Create, Read, Update, Delete) trên danh sách các công việc.
Đầu tiên,
import
các module cần thiết từ Flask và Flask-RESTful.Tiếp theo, khởi tạo một ứng dụng Flask và một API từ Flask-RESTful.
Tạo ra một danh sách TODOS chứa các công việc có sẵn, mỗi công việc có một ID duy nhất.
🤖 Tiếp theo, chương trình định nghĩa hai lớp là Todo
và TodoList
kế thừa từ lớp Resource
của Flask-RESTful:
Lớp
Todo
:get
: Trả về thông tin của một công việc cụ thể dựa trêntodo_id
.delete
: Xoá một công việc dựa trêntodo_id
.put
: Cập nhật hoặc tạo mới một công việc dựa trêntodo_id
.
TodoList
class:get
: Trả về danh sách các công việc hiện có.post
: Tạo mới một công việc và thêm vào danh sách.
🤖 Sau cùng, thiết lập các route (định tuyến) cho hai lớp TodoList
và Todo
thông qua api.add_resource()
để gán các đường dẫn URL cho từng tài nguyên (resource) tương ứng.
Để tương tác với đoạn chương trình trên, trước hết khởi chạy chương trình bằng lệnh $ python api.py
, sau đó, hãy thực thi các lệnh sau cho từng trường hợp:
GET danh sách
TODOS
$ curl http://localhost:5000/todos
GET một công việc (task)
$ curl http://localhost:5000/todos/todo3
DELETE một công việc (task)
$ curl http://localhost:5000/todos/todo2 -X DELETE -v
Thêm một công việc (task) mới
$ curl http://localhost:5000/todos -d "task=do something" -X POST -v
Cập nhật nội dung một công việc (task)
$ curl http://localhost:5000/todos/todo3 -d "task=something different" -X PUT -v
Tổng kết
Trong bài hướng dẫn này, chúng ta đã lần lượt trình bày qua những kiến thức chính và cơ bản của Flask-RESTful, gồm:
Định tuyến tài nguyên
Endpoints
Xử lý tham số đầu vào (Argument parsing)
Định dạng dữ liệu
Sau cùng, chúng ta cùng thực hành một tình huống ứng dụng - Lập trình các API cho ứng dụng quản lý công việc - để thao tác và hiểu rõ hơn cách hoạt động của Flask-RESTful, cũng như hoàn tất một chương trình "Hello World!".
Last updated