Lập Trình Flask-RESTful (Cơ Bản)
  • 🚀Giới Thiệu
  • 🤖Khởi tạo trợ lý AI cùng học lập trình
  • 💻Cài đặt môi trường lập trình
  • 🤩Hello World! - Làm quen với Flask-RESTful
  • ➡️Xử lý yêu cầu (Request parsing)
  • ⬅️Xử lý phản hồi (Output fields)
Powered by GitBook
On this page
  • Chương trình API đơn giản
  • Định tuyến tài nguyên
  • Endpoints
  • Xử lý tham số đầu vào
  • Định dạng dữ liệu
  • Chương trình "Hello World!"
  • Tổng kết

Hello World! - Làm quen với Flask-RESTful

PreviousCài đặt môi trường lập trìnhNextXử lý yêu cầu (Request parsing)

Last updated 1 year ago

Bài hướng dẫn này sẽ trình bày những bước lập trình cơ bản trên nền tảng Flask-RESTful để người đọc làm quen và khởi chạy được chương trình "Hello World!". Bài hướng dẫn cũng đính kèm cách khai thác để hỗ trợ lập trình Python và Flask-RESTful.

Khi bạn đọc thấy biểu tượng nghĩa là đoạn văn bản đó được tạo tự động bởi trên nền tảng .

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)

Bạn đọc có thể trải nghiệm AI tạo sinh văn bản bằng gợi ý (promtp) đơn giản sau:

Đóng vai là chuyên gia lập trình Flask. Hãy giải thích đoạn mã nguồn sau bằng tiếng Việt. "(chèn đoạn mã nguồn cần giải thích vào cặp ngoặc kép)"

  • Đ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 trong api và kế thừa từ Resource. Phương thức get trong class HelloWorld sẽ được gọi khi có yêu cầu GET đến địa chỉ / (địa chỉ Web cấp Root). Phương thức get 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 class HelloWorld 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ệnh app.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ế.

$ 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

Đ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)

Đóng vai là một lập trình viên Python. Hãy giải thích và cho ví dụ cấu trúc dữ liệu dict trong Python. Đồng thời liệt kê các cấu trúc dữ liệu tương tự như dict trong Python.

Đ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 -
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 kiến trúc Microservices, thuật ngữ "endpoints" thường được hiểu là các đường dẫn hoặc URL cụ thể nằm trong một dịch vụ, cho phép các dịch vụ khác hoặc các ứng dụng khác truy cập để tương tác với dịch vụ đó. Các endpoint có vai trò như các điểm đầu vào (entry points) hoặc giao diện (interface) mà các thành phần hoặc dịch vụ khác có thể sử dụng để thực hiện các hoạt động như lấy dữ liệu, gửi yêu cầu, hoặc thực thi các chức năng cụ thể. Mỗi endpoint thường biểu diễn một chức năng hoặc tài nguyên nhất định mà dịch vụ cung cấp, tạo điều kiện cho việc giao tiếp và tương tác giữa các thành phần khác nhau của hệ thống trong một kiến trúc phân tán như microservices được xác định và quản lý một cách rõ ràng.

In microservices, "endpoints" refer to specific URLs or routes within a service that other services or clients can access to interact with that service. These endpoints serve as entry points or interfaces through which different components or services can communicate and perform actions, such as retrieving data, sending requests, or executing specific functionalities. Each endpoint typically represents a particular function or resource provided by the service, allowing for a clear and well-defined way for communication and interaction between different parts of the system in a distributed architecture like microservices.

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()

Trong vai trò là lập trình viên Flask-RESTful. Hãy cho tôi biết đoạn mã "parser.parse_args()" có kết quả đầu ra là gì trong đoạn mã nguồn sau.

"(chèn đoạn mã nguồn cần giải thích vào cặp ngoặc kép)"

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)
  • Đầ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.

  1. Lớp Todo:

    • get: Trả về thông tin của một công việc cụ thể dựa trên todo_id.

    • delete: Xoá một công việc dựa trên todo_id.

    • put: Cập nhật hoặc tạo mới một công việc dựa trên todo_id.

  2. 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.

Để 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:

  1. GET danh sách TODOS

$ curl http://localhost:5000/todos
  1. GET một công việc (task)

$ curl http://localhost:5000/todos/todo3
  1. DELETE một công việc (task)

$ curl http://localhost:5000/todos/todo2 -X DELETE -v
  1. Thêm một công việc (task) mới

$ curl http://localhost:5000/todos -d "task=do something" -X POST -v
  1. 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!".

Giải thích đoạn chương trình:

Để 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 trước khi thực thi lệnh trê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 như GET, PUT.

Để hiểu thêm về cấu trúc dữ liệu dict trong Python, bạn đọc có thể sử dụng gợi ý sau để tương tác với .

Flask-RESTful còn cho phép phản hồi (response) một cách tường minh các , chẳng hạn, 200 OK hay 201 Created.

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, sẽ trình bày bằng cả tiếng Việt và tiếng Anh.

Trong kiến trúc Microservices, Endpoint là gì?

What is Endpoint in Microservices?

Đ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).

Bạn đọc có thể tương tác với bằng cách sử dụng và cải thiện đoạn gợi ý (prompt) sau:

Decorator "marshal_with()" thường được sử dụng trong các framework như Flask-RESTful để định dạng dữ liệu trước khi trả về từ một API endpoint. Decorator này thường được áp dụng cho các hàm để xử lý việc chuyển đổi dữ liệu thành định dạng mong muốn trước khi gửi về cho người dùng hoặc ứng dụng khác.

Trong lĩnh vực lập trình, DAO (Data Access Object) là một mô hình thiết kế được sử dụng để tách biệt việc truy cập vào dữ liệu từ logic của ứng dụng. Đây là một thành phần hoặc lớp có nhiệm vụ cung cấp các phương thức để thực hiện các hoạt động truy vấn và cập nhật dữ liệu trong cơ sở dữ liệu. DAO giúp tăng tính mô đun, dễ bảo trì và mở rộng của ứng dụng bằng cách cung cấp một cách tiếp cận logic và cơ sở dữ liệu một cách riêng biệt và linh hoạt.

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.

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:

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.

🤖
🤖
🤖
🤖
🤖
🤖
🤖
🤖
🤖
🤖
trợ lý AI
trợ lý AI
KamiMind
môi trường lập trình
phương thức HTTP
trợ lý AI
mã trạng thái HTTP
trợ lý AI
trợ lý AI
🤩
Page cover image
Hình minh họa trong trường hợp sử dụng tính năng "custom headers" trong phản hồi (response) trên phần mềm Postman.