Duyen Hoang

Duyen Hoang

1656757682

Cách Dễ Dàng Để Tạo Một API RESTful Với Flask Và APIFairy

Hướng dẫn này trình bày cách dễ dàng tạo một RESTful API với Flask và APIFairy.

Mục tiêu

Đến cuối hướng dẫn này, bạn sẽ có thể:

  1. Tạo điểm cuối API trong Flask bằng cách sử dụng bộ trang trí do APIFairy cung cấp
  2. Sử dụng Flask-Marshmallow để xác định các lược đồ cho đầu vào / đầu ra cho các điểm cuối API
  3. Tạo tài liệu API bằng APIFairy
  4. Tích hợp cơ sở dữ liệu quan hệ với các điểm cuối API
  5. Triển khai xác thực mã thông báo và cơ bản bằng Flask-HTTPAuth

APIFairy là gì?

APIFairy là một khung API được viết bởi Miguel Grinberg cho phép dễ dàng tạo một API với Flask.

APIFairy cung cấp bốn thành phần chính để dễ dàng tạo API trong Flask:

  1. Trang trí
  2. Lược đồ
  3. Xác thực
  4. Tài liệu

Hãy cùng khám phá chi tiết từng cái ...

Trang trí

APIFairy cung cấp một tập hợp các trình trang trí để xác định các đầu vào, đầu ra và xác thực cho mỗi điểm cuối API:

APIFairy Decorators

APIFairy cung cấp năm bộ trang trí cốt lõi:

  1. @arguments - chỉ định các đối số đầu vào trong chuỗi truy vấn của URL
  2. @body - chỉ định phần thân JSON đầu vào dưới dạng một lược đồ
  3. @response - chỉ định phần thân JSON đầu ra dưới dạng một lược đồ
  4. @other_responses - chỉ định phản hồi bổ sung (thường là lỗi) có thể được trả lại ( chỉ tài liệu )
  5. @authenticate - chỉ định quy trình xác thực

Lược đồ

Đầu vào (sử dụng trình @bodytrang trí) và đầu ra (sử dụng trình @responsetrang trí) của một điểm cuối API được định nghĩa là các lược đồ:

class EntrySchema(ma.Schema):
    """Schema defining the attributes in a journal entry."""
    id = ma.Integer()
    entry = ma.String()
    user_id = ma.Integer()

Các lược đồ sử dụng marshmallow để xác định các kiểu dữ liệu dưới dạng các lớp.

Xác thực

Trình @authenticatetrang trí được sử dụng để kiểm tra tiêu đề xác thực được cung cấp trong yêu cầu URL tới mỗi điểm cuối API. Lược đồ xác thực được triển khai bằng Flask-HTTPAuth , cũng được tạo bởi Miguel Grinberg.

Cách tiếp cận xác thực API điển hình sẽ là xác định xác thực cơ bản để bảo vệ tuyến đường truy xuất mã thông báo xác thực:

basic_auth = HTTPBasicAuth()

@basic_auth.verify_password
def verify_password(email, password):
    user = User.query.filter_by(email=email).first()
    if user.is_password_correct(password):
        return user

Và cũng để xác định xác thực mã thông báo để bảo vệ phần lớn các tuyến đường dựa trên mã thông báo xác thực nhạy cảm với thời gian:

token_auth = HTTPTokenAuth()

@token_auth.verify_token
def verify_token(auth_token):
    return User.verify_auth_token(auth_token)

Tài liệu

Một trong những tính năng tuyệt vời của APIFairy là tài liệu API tuyệt đẹp được tạo tự động:

Tài liệu API - Trang chính

Tài liệu được tạo dựa trên docstrings trong mã nguồn cùng với các biến cấu hình sau:

  1. APIFAIRY_TITLE- tên của dự án
  2. APIFAIRY_VERSION- chuỗi phiên bản của dự án
  3. APIFAIRY_UI- định dạng của tài liệu API

Đối với APIFAIRY_UI, bạn có thể tạo các mẫu từ một trong các trình kết xuất tài liệu OpenAPI sau:

  1. Giao diện người dùng Swagger
  2. ReDoc
  3. RapiDoc
  4. Các yếu tố

Để có danh sách đầy đủ các biến cấu hình có sẵn, hãy tham khảo Tài liệu cấu hình .

Chúng tôi đang xây dựng cái gì?

Bạn sẽ phát triển một API tạp chí trong hướng dẫn này, cho phép người dùng ghi nhật ký hàng ngày về các sự kiện. Bạn có thể tìm thấy mã nguồn đầy đủ trong kho lưu trữ flask-journal-api trên GitLab.

Các gói Python chính được sử dụng:

  1. Flask : khuôn khổ vi mô để phát triển ứng dụng web Python
  2. APIFairy : Khung API cho Flask, sử dụng-
  3. Flask-SQLAlchemy : ORM (Object Relational Mapper) cho Flask

Bạn sẽ phát triển API dần dần:

  1. Tạo các điểm cuối API để làm việc với các mục nhập nhật ký
  2. Tạo tài liệu API
  3. Thêm cơ sở dữ liệu quan hệ để lưu trữ các mục nhật ký
  4. Thêm xác thực để bảo vệ các điểm cuối API

Điểm cuối API

Hãy bắt đầu tạo API bằng Flask và APIFairy ...

Khởi tạo dự án

Bắt đầu bằng cách tạo một thư mục dự án mới và một môi trường ảo:

$ mkdir flask-journal-api
$ cd flask-journal-api
$ python3 -m venv venv
$ source venv/bin/activate
(venv)$

Hãy trao đổi virtualenv và Pip cho thơ hoặc Pipenv . Để biết thêm, hãy xem lại Môi trường Python hiện đại .

Tiếp tục và thêm các tệp và thư mục sau:

├── app.py
├── instance
│   └── .gitkeep
├── project
│   ├── __init__.py
│   └── journal_api
│       ├── __init__.py
│       └── routes.py
└── requirements.txt

Tiếp theo, để cài đặt các gói Python cần thiết, hãy thêm các phụ thuộc vào tệp tin request.txt trong thư mục gốc của dự án:

apifairy==0.9.1
Flask==2.1.2
Flask-SQLAlchemy==2.5.1
marshmallow-sqlalchemy==0.28.0

Cài đặt:

(venv)$ pip install -r requirements.txt

Dự án Flask này sẽ sử dụng hai phương pháp hay nhất cho các ứng dụng Flask:

  1. Application Factory - được sử dụng để tạo ứng dụng Flask trong một chức năng
  2. Bản thiết kế - được sử dụng để tổ chức một nhóm các chế độ xem liên quan

Nhà máy ứng dụng

Bắt đầu bằng cách xác định chức năng Nhà máy ứng dụng trong dự án / __ init__.py :

from apifairy import APIFairy
from flask import Flask, json
from flask_marshmallow import Marshmallow

# -------------
# Configuration
# -------------

# Create the instances of the Flask extensions in the global scope,
# but without any arguments passed in. These instances are not
# attached to the Flask application at this point.
apifairy = APIFairy()
ma = Marshmallow()


# ----------------------------
# Application Factory Function
# ----------------------------

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    initialize_extensions(app)
    register_blueprints(app)
    return app


# ----------------
# Helper Functions
# ----------------

def initialize_extensions(app):
    # Since the application instance is now created, pass it to each Flask
    # extension instance to bind it to the Flask application instance (app)
    apifairy.init_app(app)
    ma.init_app(app)


def register_blueprints(app):
    # Import the blueprints
    from project.journal_api import journal_api_blueprint

    # Since the application instance is now created, register each Blueprint
    # with the Flask application instance (app)
    app.register_blueprint(journal_api_blueprint, url_prefix='/journal')

With the Application Factory function defined, it can be called in app.py in the top-level folder of the project:

from project import create_app


# Call the application factory function to construct a Flask application
# instance using the development configuration
app = create_app()

Blueprint

Let's define the journal_api blueprint. Start by defining the journal_api blueprint in project/journal_api/__init__.py:

"""
The 'journal_api' blueprint handles the API for managing journal entries.
Specifically, this blueprint allows for journal entries to be added, edited,
and deleted.
"""
from flask import Blueprint

journal_api_blueprint = Blueprint('journal_api', __name__, template_folder='templates')

from . import routes

Now it's time to define the API endpoints for the journal in project/journal_api/routes.py.

Start with the necessary imports:

from apifairy import body, other_responses, response
from flask import abort

from project import ma
from . import journal_api_blueprint

For this initial version of the Flask Journal API, the database will be a list of journal entries:

# --------
# Database
# --------

messages = [
    dict(id=1, entry='The sun was shining when I woke up this morning.'),
    dict(id=2, entry='I tried a new fruit mixture in my oatmeal for breakfast.'),
    dict(id=3, entry='Today I ate a great sandwich for lunch.')
]

Next, define the schemas for creating a new journal entry and for returning the journal entries:

# -------
# Schemas
# -------

class NewEntrySchema(ma.Schema):
    """Schema defining the attributes when creating a new journal entry."""
    entry = ma.String(required=True)


class EntrySchema(ma.Schema):
    """Schema defining the attributes in a journal entry."""
    id = ma.Integer()
    entry = ma.String()


new_entry_schema = NewEntrySchema()
entry_schema = EntrySchema()
entries_schema = EntrySchema(many=True)

Both of these schema classes inherit from ma.Schema, which is provided by Flask-Marshmallow. It's also a good idea to create objects of these schemas, as this allows you to define a schema that can return multiple entries (using the many=True argument).

Now we're ready to define the API endpoints!

Routes

Start with retrieving all the journal entries:

@journal_api_blueprint.route('/', methods=['GET'])
@response(entries_schema)
def journal():
    """Return all journal entries"""
    return messages

This view function uses the @response decorator to define that multiple entries are returned. The view function returns the full list of journal entries (return messages).

Next, create the API endpoint for adding a new journal entry:

@journal_api_blueprint.route('/', methods=['POST'])
@body(new_entry_schema)
@response(entry_schema, 201)
def add_journal_entry(kwargs):
    """Add a new journal entry"""
    new_message = dict(**kwargs, id=messages[-1]['id']+1)
    messages.append(new_message)
    return new_message

This view function uses the @body decorator to define the input to the API endpoint and the @response decorator to define the output from the API endpoint.

The input data that is parsed from the @body decorator is passed into the add_journal_entry() view function as the kwargs (key word arguments) argument. This data is then used to create a new journal entry and add it to the database:

new_message = dict(**kwargs, id=messages[-1]['id']+1)
messages.append(new_message)

The newly created journal entry is then returned (return new_message). Notice how the @response decorator defines the return code as 201 (Created) to indicate that the journal entry was added to the database.

Create the API endpoint for retrieving a specific journal entry:

@journal_api_blueprint.route('/<int:index>', methods=['GET'])
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def get_journal_entry(index):
    """Return a journal entry"""
    if index >= len(messages):
        abort(404)

    return messages[index]

This view function uses the @other_responses decorator to specify non-standard responses.

The @other_responses decorator is only used for documentation purposes! It does not provide any functionality in terms of returning error codes.

Tạo điểm cuối API để cập nhật mục nhập tạp chí:

@journal_api_blueprint.route('/<int:index>', methods=['PUT'])
@body(new_entry_schema)
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def update_journal_entry(data, index):
    """Update a journal entry"""
    if index >= len(messages):
        abort(404)

    messages[index] = dict(data, id=index+1)
    return messages[index]

Hàm dạng xem này sử dụng bộ trang trí @bodyvà bộ @responsetrang trí để xác định các đầu vào và đầu ra (tương ứng) cho điểm cuối API này. Ngoài ra, người @other_responsestrang trí xác định phản hồi không chuẩn nếu mục nhập nhật ký không được tìm thấy.

Cuối cùng, tạo điểm cuối API để xóa mục nhập tạp chí:

@journal_api_blueprint.route('/<int:index>', methods=['DELETE'])
@other_responses({404: 'Entry not found'})
def delete_journal_entry(index):
    """Delete a journal entry"""
    if index >= len(messages):
        abort(404)

    messages.pop(index)
    return '', 204

Hàm xem này không sử dụng @body@responsedecorator, vì không có đầu vào hoặc đầu ra cho điểm cuối API này. Nếu mục nhật ký được xóa thành công, thì mã trạng thái 204 (Không có Nội dung) sẽ được trả về mà không có dữ liệu.

Chạy ứng dụng bình

Để kiểm tra mọi thứ, trong một cửa sổ đầu cuối, hãy định cấu hình ứng dụng Flask và chạy máy chủ phát triển:

(venv) $ export FLASK_APP=app.py
(venv) $ export FLASK_ENV=development
(venv) $ flask run

Sau đó, trong một cửa sổ đầu cuối khác, bạn có thể tương tác với API. Hãy thoải mái sử dụng công cụ bạn chọn tại đây, như cURL, HTTPie , Yêu cầu hoặc Người đưa thư .

Ví dụ về yêu cầu:

$ python3

>>> import requests
>>>
>>> r = requests.get('http://127.0.0.1:5000/journal/')
>>> print(r.text)
>>>
>>> post_data = {'entry': "some message"}
>>> r = requests.post('http://127.0.0.1:5000/journal/', json=post_data)
>>> print(r.text)

Bạn muốn kiểm tra các điểm cuối API dễ dàng hơn? Hãy xem tập lệnh này , tập lệnh này bổ sung các lệnh CLI để tương tác với các điểm cuối API để truy xuất, tạo, cập nhật và xóa các mục nhật ký.

Tài liệu

Một tính năng đáng kinh ngạc của APIFairy là tạo tài liệu API tự động!

Có ba khía cạnh chính để định cấu hình tài liệu API:

  1. Các chuỗi tài liệu cho các điểm cuối API (tức là các hàm xem)
  2. Chuỗi tài liệu cho dự án API tổng thể
  3. Các biến cấu hình để chỉ định giao diện của tài liệu API

We already covered the first item in the previous section since we included the docstrings for each view function. For example, the journal() view function has a short description of the purpose of this API endpoint:

@journal_api_blueprint.route('/', methods=['GET'])
@response(entries_schema)
def journal():
    """Return all journal entries"""
    return messages

Next, we need to include the docstring to describe the overall project at the very top of the project/__init__.py file:

"""
Welcome to the documentation for the Flask Journal API!

## Introduction

The Flask Journal API is an API (Application Programming Interface) for creating a **daily journal** that documents events that happen each day.

## Key Functionality

The Flask Journal API has the following functionality:

1. Work with journal entries:
  * Create a new journal entry
  * Update a journal entry
  * Delete a journal entry
  * View all journal entries
2. <More to come!>

## Key Modules

This project is written using Python 3.10.1.

The project utilizes the following modules:

* **Flask**: micro-framework for web application development which includes the following dependencies:
  * **click**: package for creating command-line interfaces (CLI)
  * **itsdangerous**: cryptographically sign data
  * **Jinja2**: templating engine
  * **MarkupSafe**: escapes characters so text is safe to use in HTML and XML
  * **Werkzeug**: set of utilities for creating a Python application that can talk to a WSGI server
* **APIFairy**: API framework for Flask which includes the following dependencies:
  * **Flask-Marshmallow** - Flask extension for using Marshmallow (object serialization/deserialization library)
  * **Flask-HTTPAuth** - Flask extension for HTTP authentication
  * **apispec** - API specification generator that supports the OpenAPI specification
* **pytest**: framework for testing Python projects
"""
...

This docstring is used to describe the overall project, including the key functionality provided and the key Python packages used by the project.

Finally, some configuration variables need to be defined to specify the look of the API documentation. Update the create_app() function in project/__init__.py:

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    # Configure the API documentation
    app.config['APIFAIRY_TITLE'] = 'Flask Journal API'
    app.config['APIFAIRY_VERSION'] = '0.1'
    app.config['APIFAIRY_UI'] = 'elements'

    initialize_extensions(app)
    register_blueprints(app)

    return app

Sẵn sàng để xem tài liệu cho dự án? Khởi động máy chủ phát triển Flask qua flask run, sau đó điều hướng đến http://127.0.0.1:5000/docs để xem tài liệu API được tạo bởi APIFairy:

Tài liệu API - Trang chính

Trên ngăn bên trái, có một danh sách các điểm cuối API cho journal_apibản thiết kế. Nhấp vào một trong các điểm cuối sẽ hiển thị tất cả thông tin chi tiết về điểm cuối đó:

Tài liệu API - Nhận điểm cuối API mục nhập nhật ký

Điều đáng ngạc nhiên về tài liệu API này là khả năng xem các điểm cuối API hoạt động như thế nào (giả sử máy chủ phát triển Flask đang chạy). Trên ngăn bên phải của tài liệu, nhập chỉ mục mục nhập tạp chí và nhấp vào "Gửi yêu cầu API". Phản hồi API sau đó được hiển thị:

Tài liệu API - Nhận phản hồi API mục nhập nhật ký

Tài liệu tương tác này giúp người dùng dễ dàng hiểu API!

Cơ sở dữ liệu

Đối với mục đích trình diễn, cơ sở dữ liệu SQLite sẽ được sử dụng trong hướng dẫn này.

Cấu hình

Flask-SQLAlchemy đã được cài đặt ở phần đầu của hướng dẫn này, chúng tôi cần phải định cấu hình nó trong tệp dự án / __ init__.py .

Bắt đầu bằng cách tạo một SQLAlchemy()đối tượng trong phần 'Cấu hình':

...

from apifairy import APIFairy
from flask import Flask, json
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy  # <-- NEW!!


# -------------
# Configuration
# -------------

# Create the instances of the Flask extensions in the global scope,
# but without any arguments passed in. These instances are not
# attached to the Flask application at this point.
apifairy = APIFairy()
ma = Marshmallow()
database = SQLAlchemy()  # <-- NEW!!

...

Tiếp theo, cập nhật create_app()hàm để chỉ định các biến cấu hình cần thiết:

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    # Configure the API documentation
    app.config['APIFAIRY_TITLE'] = 'Flask Journal API'
    app.config['APIFAIRY_VERSION'] = '0.1'
    app.config['APIFAIRY_UI'] = 'elements'

    # NEW!
    # Configure the SQLite database (intended for development only!)
    app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{os.path.join(os.getcwd(), 'instance', 'app.db')}"
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    initialize_extensions(app)
    register_blueprints(app)

    return app

Thêm nhập vào đầu:

import os

Biến SQLALCHEMY_DATABASE_URIcấu hình rất quan trọng để xác định vị trí của cơ sở dữ liệu SQLite. Đối với hướng dẫn này, cơ sở dữ liệu được lưu trữ trong instance / app.db.

Cuối cùng, cập nhật initialize_extensions()hàm để khởi tạo đối tượng Flask-SQLAlchemy:

def initialize_extensions(app):
    # Since the application instance is now created, pass it to each Flask
    # extension instance to bind it to the Flask application instance (app)
    apifairy.init_app(app)
    ma.init_app(app)
    database.init_app(app)  # <-- NEW!!

Bạn muốn tìm hiểu thêm về cách kết nối ứng dụng Flask này với nhau? Xem khóa học của tôi về cách xây dựng, kiểm tra và triển khai ứng dụng Flask:

Mô hình cơ sở dữ liệu

Tạo một tệp project / models.py mới để xác định bảng cơ sở dữ liệu đại diện cho các mục nhật ký:

from project import database


class Entry(database.Model):
    """Class that represents a journal entry."""
    __tablename__ = 'entries'

    id = database.Column(database.Integer, primary_key=True)
    entry = database.Column(database.String, nullable=False)

    def __init__(self, entry: str):
        self.entry = entry

    def update(self, entry: str):
        self.entry = entry

    def __repr__(self):
        return f'<Entry: {self.entry}>'

Lớp mới này Entry, chỉ định rằng entriesbảng cơ sở dữ liệu sẽ chứa hai phần tử (hiện tại!) Để đại diện cho một mục nhập nhật ký:

  1. id- khóa chính ( primary_key=True) cho bảng, có nghĩa là đó là mã định danh duy nhất cho mỗi phần tử (hàng) trong bảng
  2. entry- chuỗi để lưu trữ văn bản nhập nhật ký

Trong khi models.py định nghĩa bảng cơ sở dữ liệu, nó không tạo các bảng trong cơ sở dữ liệu SQLite. Để tạo bảng, hãy khởi động trình bao Flask trong cửa sổ dòng lệnh:

(venv)$ flask shell

>>> from project import database
>>> database.drop_all()
>>> database.create_all()
>>> quit()

(venv)$

Cập nhật API tạp chí

Vì chúng tôi đang tiến hành sử dụng cơ sở dữ liệu SQLite, hãy bắt đầu bằng cách xóa tạm thời database(danh sách Python) đã được xác định trong project / journal_api / route.py :

# --------
# Database
# --------

messages = [
    dict(id=1, entry='The sun was shining when I woke up this morning.'),
    dict(id=2, entry='I tried a new fruit mixture in my oatmeal for breakfast.'),
    dict(id=3, entry='Today I ate a great sandwich for lunch.')
]

Tiếp theo, chúng ta cần cập nhật từng điểm cuối API (tức là các chức năng dạng xem) để sử dụng cơ sở dữ liệu SQLite.

Bắt đầu bằng cách cập nhật journal()chức năng xem:

@journal_api_blueprint.route('/', methods=['GET'])
@response(entries_schema)
def journal():
    """Return all journal entries"""
    return Entry.query.all()

Danh sách đầy đủ các mục nhật ký hiện được truy xuất từ ​​cơ sở dữ liệu SQLite. Lưu ý rằng các lược đồ hoặc trình trang trí cho chức năng xem này không cần thay đổi như thế nào ... chỉ có quy trình cơ bản để thay đổi người dùng!

Thêm nhập khẩu:

from project.models import Entry

Tiếp theo, cập nhật add_journal_entry()chức năng xem:

@journal_api_blueprint.route('/', methods=['POST'])
@body(new_entry_schema)
@response(entry_schema, 201)
def add_journal_entry(kwargs):
    """Add a new journal entry"""
    new_message = Entry(**kwargs)
    database.session.add(new_message)
    database.session.commit()
    return new_message

Các đầu vào cho chức năng xem này được chỉ định bởi new_entry_schema:

class NewEntrySchema(ma.Schema):
    """Schema defining the attributes when creating a new journal entry."""
    entry = ma.String(required=True)

new_entry_schema = NewEntrySchema()

Chuỗi entryđược sử dụng để tạo một phiên bản mới của Entrylớp (được định nghĩa trong models.py ) và mục nhật ký này sau đó được thêm vào cơ sở dữ liệu.

Thêm nhập khẩu:

from project import database

Tiếp theo, cập nhật get_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['GET'])
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def get_journal_entry(index):
    """Return a journal entry"""
    entry = Entry.query.filter_by(id=index).first_or_404()
    return entry

Chức năng này hiện cố gắng tra cứu mục nhập nhật ký được chỉ định (dựa trên index):

entry = Entry.query.filter_by(id=index).first_or_404()

Nếu mục nhập tồn tại, nó sẽ được trả lại cho người dùng. Nếu mục nhập không tồn tại, lỗi 404 (Không tìm thấy) sẽ được trả về.

Tiếp theo, cập nhật update_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['PUT'])
@body(new_entry_schema)
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def update_journal_entry(data, index):
    """Update a journal entry"""
    entry = Entry.query.filter_by(id=index).first_or_404()
    entry.update(data['entry'])
    database.session.add(entry)
    database.session.commit()
    return entry

Chức update_journal_entry()năng xem bây giờ cố gắng truy xuất mục nhập nhật ký được chỉ định:

entry = Entry.query.filter_by(id=index).first_or_404()

Nếu mục nhật ký tồn tại, mục đó được cập nhật văn bản mới và sau đó được lưu vào cơ sở dữ liệu.

Cuối cùng, hãy cập nhật delete_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['DELETE'])
@other_responses({404: 'Entry not found'})
def delete_journal_entry(index):
    """Delete a journal entry"""
    entry = Entry.query.filter_by(id=index).first_or_404()
    database.session.delete(entry)
    database.session.commit()
    return '', 204

Nếu mục nhật ký được chỉ định được tìm thấy, thì nó sẽ bị xóa khỏi cơ sở dữ liệu.

Chạy máy chủ phát triển. Kiểm tra từng điểm cuối để đảm bảo chúng vẫn hoạt động.

Xử lý lỗi

Vì dự án Flask này là một API, mã lỗi phải được trả về ở định dạng JSON thay vì định dạng HTML điển hình.

Trong dự án Flask, điều này có thể được thực hiện bằng cách sử dụng trình xử lý lỗi tùy chỉnh. Trong project / __ init__.py , hãy xác định một hàm mới ( register_error_handlers()) ở cuối tệp:

def register_error_handlers(app):
    @app.errorhandler(HTTPException)
    def handle_http_exception(e):
        """Return JSON instead of HTML for HTTP errors."""
        # Start with the correct headers and status code from the error
        response = e.get_response()
        # Replace the body with JSON
        response.data = json.dumps({
            'code': e.code,
            'name': e.name,
            'description': e.description,
        })
        response.content_type = 'application/json'
        return response

Hàm này đăng ký một trình xử lý lỗi mới khi một HTTPExceptionđược nâng lên để chuyển đổi đầu ra thành định dạng JSON.

Thêm nhập khẩu:

from werkzeug.exceptions import HTTPException

Ngoài ra, hãy cập nhật chức năng Nhà máy ứng dụng create_app(), để gọi chức năng mới này:

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    # Configure the API documentation
    app.config['APIFAIRY_TITLE'] = 'Flask Journal API'
    app.config['APIFAIRY_VERSION'] = '0.1'
    app.config['APIFAIRY_UI'] = 'elements'

    # Configure the SQLite database (intended for development only!)
    app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{os.path.join(os.getcwd(), 'instance', 'app.db')}"
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    initialize_extensions(app)
    register_blueprints(app)
    register_error_handlers(app)  # NEW!!

    return app

Xác thực

Authentication is the process of validating the identity of a user attempting to access a system, which in this case is the API.

Authorization, on the other hand, is the process of verifying what specific resources a specific user should have access to.

APIFairy utilizes Flask-HTTPAuth for authentication support. In this tutorial, we'll be using Flask-HTTPAuth in two manners:

  1. Basic Authentication - used to generate a token based on the user's email/password
  2. Token Authentication - used to authenticate the user on all other API endpoints

Xác thực mã thông báo được sử dụng qua Flask-HTTPAuth thường được gọi là Xác thực mang, vì quá trình này yêu cầu cấp quyền truy cập cho "người mang" mã thông báo. Mã thông báo phải được bao gồm trong tiêu đề HTTP trong tiêu đề Ủy quyền, chẳng hạn như "Ủy quyền: Người mang".

Sơ đồ sau minh họa một quy trình điển hình về cách người dùng mới tương tác với ứng dụng để truy xuất mã thông báo xác thực:

Sơ đồ luồng API của tạp chí Flask

Cấu hình

Vì Flask-HTTPAuth đã được cài đặt khi APIFairy được cài đặt ở phần đầu của hướng dẫn này, chúng tôi chỉ cần định cấu hình nó trong tệp dự án / __ init__.py .

Bắt đầu bằng cách tạo các đối tượng riêng biệt để xác thực mã thông báo và cơ bản:

...

import os

from apifairy import APIFairy
from flask import Flask, json
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth  # NEW!!
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from werkzeug.exceptions import HTTPException


# -------------
# Configuration
# -------------

# Create the instances of the Flask extensions in the global scope,
# but without any arguments passed in. These instances are not
# attached to the Flask application at this point.
apifairy = APIFairy()
ma = Marshmallow()
database = SQLAlchemy()
basic_auth = HTTPBasicAuth()  # NEW!!
token_auth = HTTPTokenAuth()  # NEW!!

...

Không cần cập nhật thêm trong dự án / __ init__.py .

Mô hình cơ sở dữ liệu

Trong project / models.py , một Usermô hình mới cần được tạo để đại diện cho người dùng:

class User(database.Model):
    __tablename__ = 'users'

    id = database.Column(database.Integer, primary_key=True)
    email = database.Column(database.String, unique=True, nullable=False)
    password_hashed = database.Column(database.String(128), nullable=False)
    entries = database.relationship('Entry', backref='user', lazy='dynamic')
    auth_token = database.Column(database.String(64), index=True)
    auth_token_expiration = database.Column(database.DateTime)

    def __init__(self, email: str, password_plaintext: str):
        """Create a new User object."""
        self.email = email
        self.password_hashed = self._generate_password_hash(password_plaintext)

    def is_password_correct(self, password_plaintext: str):
        return check_password_hash(self.password_hashed, password_plaintext)

    def set_password(self, password_plaintext: str):
        self.password_hashed = self._generate_password_hash(password_plaintext)

    @staticmethod
    def _generate_password_hash(password_plaintext):
        return generate_password_hash(password_plaintext)

    def generate_auth_token(self):
        self.auth_token = secrets.token_urlsafe()
        self.auth_token_expiration = datetime.utcnow() + timedelta(minutes=60)
        return self.auth_token

    @staticmethod
    def verify_auth_token(auth_token):
        user = User.query.filter_by(auth_token=auth_token).first()
        if user and user.auth_token_expiration > datetime.utcnow():
            return user

    def revoke_auth_token(self):
        self.auth_token_expiration = datetime.utcnow()

    def __repr__(self):
        return f'<User: {self.email}>'

Thêm nhập khẩu:

import secrets
from datetime import datetime, timedelta

from werkzeug.security import check_password_hash, generate_password_hash

Userhình sử dụng werkzeug.securityđể băm mật khẩu của người dùng trước khi lưu trữ trong cơ sở dữ liệu.

Hãy nhớ: Không bao giờ lưu trữ mật khẩu văn bản rõ trong cơ sở dữ liệu!

Userhình sử dụng secretsđể tạo mã thông báo xác thực cho một người dùng cụ thể. Mã thông báo này được tạo trong generate_auth_token()phương thức và bao gồm ngày / giờ hết hạn là 60 phút trong tương lai:

def generate_auth_token(self):
    self.auth_token = secrets.token_urlsafe()
    self.auth_token_expiration = datetime.utcnow() + timedelta(minutes=60)
    return self.auth_token

Có một phương thức tĩnh, verify_auth_token()được sử dụng để xác minh mã thông báo xác thực (trong khi xem xét thời gian hết hạn) và trả lại người dùng từ mã thông báo hợp lệ:

@staticmethod
def verify_auth_token(auth_token):
    user = User.query.filter_by(auth_token=auth_token).first()
    if user and user.auth_token_expiration > datetime.utcnow():
        return user

Một phương pháp quan tâm khác là revoke_auth_token(), được sử dụng để thu hồi mã thông báo xác thực cho một người dùng cụ thể:

def revoke_auth_token(self):
    self.auth_token_expiration = datetime.utcnow()

Mô hình nhập cảnh

Để thiết lập mối quan hệ một-nhiều giữa người dùng ("một") và các mục nhập của họ ("nhiều"), Entrymô hình cần được cập nhật để liên kết các bảng entriesusersvới nhau:

class Entry(database.Model):
    """Class that represents a journal entry."""
    __tablename__ = 'entries'

    id = database.Column(database.Integer, primary_key=True)
    entry = database.Column(database.String, nullable=False)
    user_id = database.Column(database.Integer, database.ForeignKey('users.id'))  # <-- NEW!!

    def __init__(self, entry: str):
        self.entry = entry

    def update(self, entry: str):
        self.entry = entry

    def __repr__(self):
        return f'<Entry: {self.entry}>'

Userhình đã chứa liên kết quay lại entriesbảng:

entries = database.relationship('Entry', backref='user', lazy='dynamic')

Bản thiết kế API người dùng

Chức năng quản lý người dùng của dự án Flask sẽ được định nghĩa trong một Bản thiết kế riêng được gọi là users_api_blueprint.

Bắt đầu bằng cách tạo một thư mục mới trong "dự án" được gọi là "users_api". Trong thư mục đó, hãy tạo một tệp __init__.py :

from flask import Blueprint


users_api_blueprint = Blueprint('users_api', __name__)

from . import authentication, routes

Bản kế hoạch chi tiết mới này cần được đăng ký với Flask apptrong các dự án / __ init__.py trong register_blueprints()hàm:

def register_blueprints(app):
    # Import the blueprints
    from project.journal_api import journal_api_blueprint
    from project.users_api import users_api_blueprint  # NEW!!

    # Since the application instance is now created, register each Blueprint
    # with the Flask application instance (app)
    app.register_blueprint(journal_api_blueprint, url_prefix='/journal')
    app.register_blueprint(users_api_blueprint, url_prefix='/users')  # NEW!!

Chức năng xác thực

Để sử dụng Flask-HTTPAuth, một số chức năng cần được xác định để xử lý việc kiểm tra thông tin đăng nhập của người dùng.

Tạo một tệp dự án / users_api / verify.py mới để xử lý xác thực cơ bản và xác thực mã thông báo.

Đối với xác thực cơ bản (kiểm tra email và mật khẩu của người dùng):

from werkzeug.exceptions import Forbidden, Unauthorized

from project import basic_auth, token_auth
from project.models import User


@basic_auth.verify_password
def verify_password(email, password):
    user = User.query.filter_by(email=email).first()
    if user is None:
        return None

    if user.is_password_correct(password):
        return user


@basic_auth.error_handler
def basic_auth_error(status=401):
    error = (Forbidden if status == 403 else Unauthorized)()
    return {
        'code': error.code,
        'message': error.name,
        'description': error.description,
    }, error.code, {'WWW-Authenticate': 'Form'}

Hàm verify_password()được sử dụng để kiểm tra xem người dùng có tồn tại và mật khẩu của họ có chính xác hay không. Chức năng này sẽ được sử dụng bởi Flask-HTTPAuth để xác minh mật khẩu khi cần xác thực cơ bản (nhờ trình @basic_auth.verify_passwordtrang trí).

Ngoài ra, một trình xử lý lỗi được xác định cho xác thực cơ bản trả về thông tin về lỗi ở định dạng JSON.

Đối với xác thực mã thông báo (xử lý mã thông báo để xác định xem người dùng có hợp lệ hay không):

@token_auth.verify_token
def verify_token(auth_token):
    return User.verify_auth_token(auth_token)


@token_auth.error_handler
def token_auth_error(status=401):
    error = (Forbidden if status == 403 else Unauthorized)()
    return {
        'code': error.code,
        'message': error.name,
        'description': error.description,
    }, error.code

Hàm verify_token()được sử dụng để kiểm tra xem mã thông báo xác thực có hợp lệ hay không. Chức năng này sẽ được sử dụng bởi Flask-HTTPAuth để xác minh mã thông báo khi cần xác thực mã thông báo (nhờ trình @token_auth.verify_tokentrang trí).

Ngoài ra, một trình xử lý lỗi được xác định để xác thực mã thông báo trả về thông tin về lỗi ở định dạng JSON.

Các tuyến đường của người dùng

Trong users_api_blueprint, sẽ có hai tuyến đường:

  1. Đăng ký người dùng mới
  2. Truy xuất mã thông báo xác thực

Để bắt đầu, một tập hợp các lược đồ mới (sử dụng marshmallow) cần được xác định trong các dự án / users_api / route.py :

from project import ma

from . import users_api_blueprint

# -------
# Schemas
# -------

class NewUserSchema(ma.Schema):
    """Schema defining the attributes when creating a new user."""
    email = ma.String()
    password_plaintext = ma.String()


class UserSchema(ma.Schema):
    """Schema defining the attributes of a user."""
    id = ma.Integer()
    email = ma.String()


class TokenSchema(ma.Schema):
    """Schema defining the attributes of a token."""
    token = ma.String()


new_user_schema = NewUserSchema()
user_schema = UserSchema()
token_schema = TokenSchema()

Các lược đồ này sẽ được sử dụng để xác định các đầu vào và đầu ra cho các chức năng dạng xem được xác định trong tệp này.

Đăng ký người dùng mới

Tiếp theo, xác định chức năng xem để đăng ký người dùng mới:

@users_api_blueprint.route('/', methods=['POST'])
@body(new_user_schema)
@response(user_schema, 201)
def register(kwargs):
    """Create a new user"""
    new_user = User(**kwargs)
    database.session.add(new_user)
    database.session.commit()
    return new_user

Thêm nhập khẩu:

from apifairy import authenticate, body, other_responses, response

from project import basic_auth, database, ma
from project.models import User

Điểm cuối API này sử dụng new_user_schemađể chỉ định rằng email và mật khẩu là đầu vào.

LƯU Ý: Vì email và mật khẩu được gửi đến điểm cuối API này, nên nhớ rằng việc sử dụng HTTP được chấp nhận trong quá trình thử nghiệm phát triển, nhưng HTTPS (bảo mật) phải luôn được sử dụng trong quá trình sản xuất.

Sau đó, email và mật khẩu (được định nghĩa là kwargsđối số - từ khóa) được giải nén để tạo một Userđối tượng mới, được lưu vào cơ sở dữ liệu:

new_user = User(**kwargs)
database.session.add(new_user)
database.session.commit()

Đầu ra từ điểm cuối API được xác định bởi user_schema, đó là ID và email cho người dùng mới.

Truy xuất mã thông báo xác thực

Chức năng xem khác để xác định trong các dự án / users_api / route.py là để truy xuất mã thông báo xác thực:

@users_api_blueprint.route('/get-auth-token', methods=['POST'])
@authenticate(basic_auth)
@response(token_schema)
@other_responses({401: 'Invalid username or password'})
def get_auth_token():
    """Get authentication token"""
    user = basic_auth.current_user()
    token = user.generate_auth_token()
    database.session.add(user)
    database.session.commit()
    return dict(token=token)

Trình @authenticatetrang trí được sử dụng lần đầu tiên trong hướng dẫn này và nó chỉ định rằng xác thực cơ bản nên được sử dụng để bảo vệ tuyến đường này:

@authenticate(basic_auth)

Khi người dùng muốn truy xuất mã thông báo xác thực của họ, họ cần gửi yêu cầu ĐĂNG tới điểm cuối API này với email và mật khẩu được nhúng trong tiêu đề 'Ủy quyền'. Ví dụ: lệnh Python sau sử dụng gói Yêu cầu có thể được thực hiện cho điểm cuối API này:

>>> import requests
>>> r = requests.post(
    'http://127.0.0.1:5000/users/get-auth-token',
    auth=('pkennedy@hey.com', 'FlaskIsAwesome123')
)

Nếu xác thực cơ bản thành công, chức năng xem sẽ truy xuất người dùng hiện tại bằng current_user()phương pháp được cung cấp bởi Flask-HTTPAuth:

user = basic_auth.current_user()

Mã thông báo xác thực mới được tạo cho người dùng đó:

token = user.generate_auth_token()

Và mã thông báo đó được lưu vào cơ sở dữ liệu để nó có thể được sử dụng để xác thực người dùng trong tương lai (ít nhất là trong 60 phút tới!).

Cuối cùng, mã thông báo xác thực mới được trả lại để người dùng lưu cho tất cả các lệnh gọi API tiếp theo.

Cập nhật điểm cuối API

Với quy trình xác thực đã có, đã đến lúc thêm một số bảo vệ vào các điểm cuối API hiện có để đảm bảo rằng chỉ những người dùng hợp lệ mới có thể truy cập ứng dụng.

Các cập nhật này dành cho các chức năng xem được xác định trong các dự án / journal_api / route.py .

Đầu tiên, hãy cập nhật journal()để chỉ trả lại các mục nhật ký cho người dùng hiện tại:

@journal_api_blueprint.route('/', methods=['GET'])
@authenticate(token_auth)
@response(entries_schema)
def journal():
    """Return journal entries"""
    user = token_auth.current_user()
    return Entry.query.filter_by(user_id=user.id).all()

Cập nhật các nhập ở trên cùng như sau:

from apifairy import authenticate, body, other_responses, response
from flask import abort

from project import database, ma, token_auth
from project.models import Entry

from . import journal_api_blueprint

Người @authenticatetrang trí chỉ định rằng xác thực mã thông báo cần được sử dụng khi truy cập điểm cuối API này. Ví dụ: yêu cầu GET sau có thể được thực hiện bằng Yêu cầu ( sau khi mã thông báo xác thực đã được truy xuất ):

>>> import requests
>>> headers = {'Authorization': f'Bearer {auth_token}'}
>>> r = requests.get('http://127.0.0.1:5000/journal/', headers=headers)

Sau khi người dùng được xác thực, danh sách đầy đủ các mục nhật ký sẽ được truy xuất từ ​​cơ sở dữ liệu dựa trên ID của người dùng:

user = token_auth.current_user()
return Entry.query.filter_by(user_id=user.id).all()

Đầu ra từ điểm cuối API này được xác định bởi người @responsetrang trí, là danh sách các mục nhật ký (ID, mục nhập, ID người dùng).

Tiếp theo, cập nhật add_journal_entry():

@journal_api_blueprint.route('/', methods=['POST'])
@authenticate(token_auth)
@body(new_entry_schema)
@response(entry_schema, 201)
def add_journal_entry(kwargs):
    """Add a new journal entry"""
    user = token_auth.current_user()
    new_message = Entry(user_id=user.id, **kwargs)
    database.session.add(new_message)
    database.session.commit()
    return new_message

Như với chức năng xem trước, trình @authenticatetrang trí được sử dụng để chỉ định rằng xác thực mã thông báo cần được sử dụng khi truy cập điểm cuối API này. Ngoài ra, mục nhập tạp chí hiện được thêm vào bằng cách chỉ định ID người dùng sẽ được liên kết với mục nhập tạp chí:

user = token_auth.current_user()
new_message = Entry(user_id=user.id, **kwargs)

Mục nhật ký mới được lưu vào cơ sở dữ liệu và mục nhập nhật ký được trả lại (theo định nghĩa của người @responsetrang trí).

Tiếp theo, cập nhật get_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['GET'])
@authenticate(token_auth)
@response(entry_schema)
@other_responses({403: 'Forbidden', 404: 'Entry not found'})
def get_journal_entry(index):
    """Return a journal entry"""
    user = token_auth.current_user()
    entry = Entry.query.filter_by(id=index).first_or_404()

    if entry.user_id != user.id:
        abort(403)
    return entry

Trình @authenticatetrang trí được thêm vào để chỉ định rằng cần xác thực mã thông báo để truy cập điểm cuối API này.

Khi cố gắng truy xuất mục nhập nhật ký, một kiểm tra bổ sung được thêm vào để đảm bảo rằng người dùng cố gắng truy cập mục nhập nhật ký là "chủ sở hữu" thực sự của mục nhập. Nếu không, thì mã lỗi 403 (Bị cấm) được trả về thông qua abort()hàm từ Flask:

if entry.user_id != user.id:
        abort(403)

Hãy lưu ý rằng điểm cuối API này có hai phản hồi ngoài danh nghĩa được chỉ định bởi người @other_responsestrang trí:

@other_responses({403: 'Forbidden', 404: 'Entry not found'})

Nhắc nhở: Trình @other_responsestrang trí chỉ dành cho tài liệu; đó là trách nhiệm của chức năng xem để tạo ra những lỗi này.

Tiếp theo, cập nhật update_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['PUT'])
@authenticate(token_auth)
@body(new_entry_schema)
@response(entry_schema)
@other_responses({403: 'Forbidden', 404: 'Entry not found'})
def update_journal_entry(data, index):
    """Update a journal entry"""
    user = token_auth.current_user()
    entry = Entry.query.filter_by(id=index).first_or_404()

    if entry.user_id != user.id:
        abort(403)

    entry.update(data['entry'])
    database.session.add(entry)
    database.session.commit()
    return entry

Các cập nhật cho chức năng xem này tương tự như các chức năng xem khác trong phần này:

  1. @authenticatedecorator chỉ định rằng xác thực mã thông báo là cần thiết để truy cập điểm cuối API này
  2. Chỉ người dùng "sở hữu" mục nhập mới được phép cập nhật mục nhập (nếu không, 403 (Bị cấm))

Cuối cùng, hãy cập nhật delete_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['DELETE'])
@authenticate(token_auth)
@other_responses({403: 'Forbidden', 404: 'Entry not found'})
def delete_journal_entry(index):
    """Delete a journal entry"""
    user = token_auth.current_user()
    entry = Entry.query.filter_by(id=index).first_or_404()

    if entry.user_id != user.id:
        abort(403)

    database.session.delete(entry)
    database.session.commit()
    return '', 204

Sự kết luận

Hướng dẫn này đã cung cấp hướng dẫn về cách dễ dàng và nhanh chóng xây dựng một API trong Flask bằng APIFairy.

Trình trang trí là chìa khóa để xác định các điểm cuối API:

  • Đầu vào :
    • @arguments- đầu vào đối số từ chuỗi truy vấn của URL
    • @body- cấu trúc của yêu cầu JSON
  • Kết quả đầu ra :
    • @response- cấu trúc của phản hồi JSON
  • Xác thực :
    • @authenticate- phương pháp xác thực sử dụng Flask-HTTPAuth
  • Các lỗi :
    • @other_responses- phản hồi ngoài danh nghĩa, chẳng hạn như mã lỗi HTTP

Thêm vào đó, tài liệu API do APIFairy tạo ra rất tuyệt vời và cung cấp thông tin chính cho người dùng ứng dụng.

Nguồn:  https://testdriven.io

#api #flask 

What is GEEK

Buddha Community

Cách Dễ Dàng Để Tạo Một API RESTful Với Flask Và APIFairy
Wilford  Pagac

Wilford Pagac

1594289280

What is REST API? An Overview | Liquid Web

What is REST?

The REST acronym is defined as a “REpresentational State Transfer” and is designed to take advantage of existing HTTP protocols when used for Web APIs. It is very flexible in that it is not tied to resources or methods and has the ability to handle different calls and data formats. Because REST API is not constrained to an XML format like SOAP, it can return multiple other formats depending on what is needed. If a service adheres to this style, it is considered a “RESTful” application. REST allows components to access and manage functions within another application.

REST was initially defined in a dissertation by Roy Fielding’s twenty years ago. He proposed these standards as an alternative to SOAP (The Simple Object Access Protocol is a simple standard for accessing objects and exchanging structured messages within a distributed computing environment). REST (or RESTful) defines the general rules used to regulate the interactions between web apps utilizing the HTTP protocol for CRUD (create, retrieve, update, delete) operations.

What is an API?

An API (or Application Programming Interface) provides a method of interaction between two systems.

What is a RESTful API?

A RESTful API (or application program interface) uses HTTP requests to GET, PUT, POST, and DELETE data following the REST standards. This allows two pieces of software to communicate with each other. In essence, REST API is a set of remote calls using standard methods to return data in a specific format.

The systems that interact in this manner can be very different. Each app may use a unique programming language, operating system, database, etc. So, how do we create a system that can easily communicate and understand other apps?? This is where the Rest API is used as an interaction system.

When using a RESTful API, we should determine in advance what resources we want to expose to the outside world. Typically, the RESTful API service is implemented, keeping the following ideas in mind:

  • Format: There should be no restrictions on the data exchange format
  • Implementation: REST is based entirely on HTTP
  • Service Definition: Because REST is very flexible, API can be modified to ensure the application understands the request/response format.
  • The RESTful API focuses on resources and how efficiently you perform operations with it using HTTP.

The features of the REST API design style state:

  • Each entity must have a unique identifier.
  • Standard methods should be used to read and modify data.
  • It should provide support for different types of resources.
  • The interactions should be stateless.

For REST to fit this model, we must adhere to the following rules:

  • Client-Server Architecture: The interface is separate from the server-side data repository. This affords flexibility and the development of components independently of each other.
  • Detachment: The client connections are not stored on the server between requests.
  • Cacheability: It must be explicitly stated whether the client can store responses.
  • Multi-level: The API should work whether it interacts directly with a server or through an additional layer, like a load balancer.

#tutorials #api #application #application programming interface #crud #http #json #programming #protocols #representational state transfer #rest #rest api #rest api graphql #rest api json #rest api xml #restful #soap #xml #yaml

An API-First Approach For Designing Restful APIs | Hacker Noon

I’ve been working with Restful APIs for some time now and one thing that I love to do is to talk about APIs.

So, today I will show you how to build an API using the API-First approach and Design First with OpenAPI Specification.

First thing first, if you don’t know what’s an API-First approach means, it would be nice you stop reading this and check the blog post that I wrote to the Farfetchs blog where I explain everything that you need to know to start an API using API-First.

Preparing the ground

Before you get your hands dirty, let’s prepare the ground and understand the use case that will be developed.

Tools

If you desire to reproduce the examples that will be shown here, you will need some of those items below.

  • NodeJS
  • OpenAPI Specification
  • Text Editor (I’ll use VSCode)
  • Command Line

Use Case

To keep easy to understand, let’s use the Todo List App, it is a very common concept beyond the software development community.

#api #rest-api #openai #api-first-development #api-design #apis #restful-apis #restful-api

Lets Cms

Lets Cms

1652251528

Opencart REST API extensions - V3.x | Rest API Integration, Affiliate

Opencart REST API extensions - V3.x | Rest API Integration : OpenCart APIs is fully integrated with the OpenCart REST API. This is interact with your OpenCart site by sending and receiving data as JSON (JavaScript Object Notation) objects. Using the OpenCart REST API you can register the customers and purchasing the products and it provides data access to the content of OpenCart users like which is publicly accessible via the REST API. This APIs also provide the E-commerce Mobile Apps.

Opencart REST API 
OCRESTAPI Module allows the customer purchasing product from the website it just like E-commerce APIs its also available mobile version APIs.

Opencart Rest APIs List 
Customer Registration GET APIs.
Customer Registration POST APIs.
Customer Login GET APIs.
Customer Login POST APIs.
Checkout Confirm GET APIs.
Checkout Confirm POST APIs.


If you want to know Opencart REST API Any information, you can contact us at -
Skype: jks0586,
Email: letscmsdev@gmail.com,
Website: www.letscms.com, www.mlmtrees.com
Call/WhatsApp/WeChat: +91–9717478599.

Download : https://www.opencart.com/index.php?route=marketplace/extension/info&extension_id=43174&filter_search=ocrest%20api
View Documentation : https://www.letscms.com/documents/api/opencart-rest-api.html
More Information : https://www.letscms.com/blog/Rest-API-Opencart
VEDIO : https://vimeo.com/682154292  

#opencart_api_for_android #Opencart_rest_admin_api #opencart_rest_api #Rest_API_Integration #oc_rest_api #rest_api_ecommerce #rest_api_mobile #rest_api_opencart #rest_api_github #rest_api_documentation #opencart_rest_admin_api #rest_api_for_opencart_mobile_app #opencart_shopping_cart_rest_api #opencart_json_api

Lets Cms

Lets Cms

1652251629

Unilevel MLM Wordpress Rest API FrontEnd | UMW Rest API Woocommerce

Unilevel MLM Wordpress Rest API FrontEnd | UMW Rest API Woocommerce Price USA, Philippines : Our API’s handle the Unilevel MLM woo-commerce end user all functionalities like customer login/register. You can request any type of information which is listed below, our API will provide you managed results for your all frontend needs, which will be useful for your applications like Mobile App etc.
Business to Customer REST API for Unilevel MLM Woo-Commerce will empower your Woo-commerce site with the most powerful Unilevel MLM Woo-Commerce REST API, you will be able to get and send data to your marketplace from other mobile apps or websites using HTTP Rest API request.
Our plugin is used JWT authentication for the authorization process.

REST API Unilevel MLM Woo-commerce plugin contains following APIs.
User Login Rest API
User Register Rest API
User Join Rest API
Get User info Rest API
Get Affiliate URL Rest API 
Get Downlines list Rest API
Get Bank Details Rest API
Save Bank Details Rest API
Get Genealogy JSON Rest API
Get Total Earning Rest API
Get Current Balance Rest API
Get Payout Details Rest API
Get Payout List Rest API
Get Commissions List Rest API
Withdrawal Request Rest API
Get Withdrawal List Rest API

If you want to know more information and any queries regarding Unilevel MLM Rest API Woocommerce WordPress Plugin, you can contact our experts through 
Skype: jks0586, 
Mail: letscmsdev@gmail.com,
Website: www.letscms.com, www.mlmtrees.com,
Call/WhatsApp/WeChat: +91-9717478599.  

more information : https://www.mlmtrees.com/product/unilevel-mlm-woocommerce-rest-api-addon

Visit Documentation : https://letscms.com/documents/umw_apis/umw-apis-addon-documentation.html

#Unilevel_MLM_WooCommerce_Rest_API's_Addon #umw_mlm_rest_api #rest_api_woocommerce_unilevel #rest_api_in_woocommerce #rest_api_woocommerce #rest_api_woocommerce_documentation #rest_api_woocommerce_php #api_rest_de_woocommerce #woocommerce_rest_api_in_android #woocommerce_rest_api_in_wordpress #Rest_API_Woocommerce_unilevel_mlm #wp_rest_api_woocommerce

Duyen Hoang

Duyen Hoang

1656757682

Cách Dễ Dàng Để Tạo Một API RESTful Với Flask Và APIFairy

Hướng dẫn này trình bày cách dễ dàng tạo một RESTful API với Flask và APIFairy.

Mục tiêu

Đến cuối hướng dẫn này, bạn sẽ có thể:

  1. Tạo điểm cuối API trong Flask bằng cách sử dụng bộ trang trí do APIFairy cung cấp
  2. Sử dụng Flask-Marshmallow để xác định các lược đồ cho đầu vào / đầu ra cho các điểm cuối API
  3. Tạo tài liệu API bằng APIFairy
  4. Tích hợp cơ sở dữ liệu quan hệ với các điểm cuối API
  5. Triển khai xác thực mã thông báo và cơ bản bằng Flask-HTTPAuth

APIFairy là gì?

APIFairy là một khung API được viết bởi Miguel Grinberg cho phép dễ dàng tạo một API với Flask.

APIFairy cung cấp bốn thành phần chính để dễ dàng tạo API trong Flask:

  1. Trang trí
  2. Lược đồ
  3. Xác thực
  4. Tài liệu

Hãy cùng khám phá chi tiết từng cái ...

Trang trí

APIFairy cung cấp một tập hợp các trình trang trí để xác định các đầu vào, đầu ra và xác thực cho mỗi điểm cuối API:

APIFairy Decorators

APIFairy cung cấp năm bộ trang trí cốt lõi:

  1. @arguments - chỉ định các đối số đầu vào trong chuỗi truy vấn của URL
  2. @body - chỉ định phần thân JSON đầu vào dưới dạng một lược đồ
  3. @response - chỉ định phần thân JSON đầu ra dưới dạng một lược đồ
  4. @other_responses - chỉ định phản hồi bổ sung (thường là lỗi) có thể được trả lại ( chỉ tài liệu )
  5. @authenticate - chỉ định quy trình xác thực

Lược đồ

Đầu vào (sử dụng trình @bodytrang trí) và đầu ra (sử dụng trình @responsetrang trí) của một điểm cuối API được định nghĩa là các lược đồ:

class EntrySchema(ma.Schema):
    """Schema defining the attributes in a journal entry."""
    id = ma.Integer()
    entry = ma.String()
    user_id = ma.Integer()

Các lược đồ sử dụng marshmallow để xác định các kiểu dữ liệu dưới dạng các lớp.

Xác thực

Trình @authenticatetrang trí được sử dụng để kiểm tra tiêu đề xác thực được cung cấp trong yêu cầu URL tới mỗi điểm cuối API. Lược đồ xác thực được triển khai bằng Flask-HTTPAuth , cũng được tạo bởi Miguel Grinberg.

Cách tiếp cận xác thực API điển hình sẽ là xác định xác thực cơ bản để bảo vệ tuyến đường truy xuất mã thông báo xác thực:

basic_auth = HTTPBasicAuth()

@basic_auth.verify_password
def verify_password(email, password):
    user = User.query.filter_by(email=email).first()
    if user.is_password_correct(password):
        return user

Và cũng để xác định xác thực mã thông báo để bảo vệ phần lớn các tuyến đường dựa trên mã thông báo xác thực nhạy cảm với thời gian:

token_auth = HTTPTokenAuth()

@token_auth.verify_token
def verify_token(auth_token):
    return User.verify_auth_token(auth_token)

Tài liệu

Một trong những tính năng tuyệt vời của APIFairy là tài liệu API tuyệt đẹp được tạo tự động:

Tài liệu API - Trang chính

Tài liệu được tạo dựa trên docstrings trong mã nguồn cùng với các biến cấu hình sau:

  1. APIFAIRY_TITLE- tên của dự án
  2. APIFAIRY_VERSION- chuỗi phiên bản của dự án
  3. APIFAIRY_UI- định dạng của tài liệu API

Đối với APIFAIRY_UI, bạn có thể tạo các mẫu từ một trong các trình kết xuất tài liệu OpenAPI sau:

  1. Giao diện người dùng Swagger
  2. ReDoc
  3. RapiDoc
  4. Các yếu tố

Để có danh sách đầy đủ các biến cấu hình có sẵn, hãy tham khảo Tài liệu cấu hình .

Chúng tôi đang xây dựng cái gì?

Bạn sẽ phát triển một API tạp chí trong hướng dẫn này, cho phép người dùng ghi nhật ký hàng ngày về các sự kiện. Bạn có thể tìm thấy mã nguồn đầy đủ trong kho lưu trữ flask-journal-api trên GitLab.

Các gói Python chính được sử dụng:

  1. Flask : khuôn khổ vi mô để phát triển ứng dụng web Python
  2. APIFairy : Khung API cho Flask, sử dụng-
  3. Flask-SQLAlchemy : ORM (Object Relational Mapper) cho Flask

Bạn sẽ phát triển API dần dần:

  1. Tạo các điểm cuối API để làm việc với các mục nhập nhật ký
  2. Tạo tài liệu API
  3. Thêm cơ sở dữ liệu quan hệ để lưu trữ các mục nhật ký
  4. Thêm xác thực để bảo vệ các điểm cuối API

Điểm cuối API

Hãy bắt đầu tạo API bằng Flask và APIFairy ...

Khởi tạo dự án

Bắt đầu bằng cách tạo một thư mục dự án mới và một môi trường ảo:

$ mkdir flask-journal-api
$ cd flask-journal-api
$ python3 -m venv venv
$ source venv/bin/activate
(venv)$

Hãy trao đổi virtualenv và Pip cho thơ hoặc Pipenv . Để biết thêm, hãy xem lại Môi trường Python hiện đại .

Tiếp tục và thêm các tệp và thư mục sau:

├── app.py
├── instance
│   └── .gitkeep
├── project
│   ├── __init__.py
│   └── journal_api
│       ├── __init__.py
│       └── routes.py
└── requirements.txt

Tiếp theo, để cài đặt các gói Python cần thiết, hãy thêm các phụ thuộc vào tệp tin request.txt trong thư mục gốc của dự án:

apifairy==0.9.1
Flask==2.1.2
Flask-SQLAlchemy==2.5.1
marshmallow-sqlalchemy==0.28.0

Cài đặt:

(venv)$ pip install -r requirements.txt

Dự án Flask này sẽ sử dụng hai phương pháp hay nhất cho các ứng dụng Flask:

  1. Application Factory - được sử dụng để tạo ứng dụng Flask trong một chức năng
  2. Bản thiết kế - được sử dụng để tổ chức một nhóm các chế độ xem liên quan

Nhà máy ứng dụng

Bắt đầu bằng cách xác định chức năng Nhà máy ứng dụng trong dự án / __ init__.py :

from apifairy import APIFairy
from flask import Flask, json
from flask_marshmallow import Marshmallow

# -------------
# Configuration
# -------------

# Create the instances of the Flask extensions in the global scope,
# but without any arguments passed in. These instances are not
# attached to the Flask application at this point.
apifairy = APIFairy()
ma = Marshmallow()


# ----------------------------
# Application Factory Function
# ----------------------------

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    initialize_extensions(app)
    register_blueprints(app)
    return app


# ----------------
# Helper Functions
# ----------------

def initialize_extensions(app):
    # Since the application instance is now created, pass it to each Flask
    # extension instance to bind it to the Flask application instance (app)
    apifairy.init_app(app)
    ma.init_app(app)


def register_blueprints(app):
    # Import the blueprints
    from project.journal_api import journal_api_blueprint

    # Since the application instance is now created, register each Blueprint
    # with the Flask application instance (app)
    app.register_blueprint(journal_api_blueprint, url_prefix='/journal')

With the Application Factory function defined, it can be called in app.py in the top-level folder of the project:

from project import create_app


# Call the application factory function to construct a Flask application
# instance using the development configuration
app = create_app()

Blueprint

Let's define the journal_api blueprint. Start by defining the journal_api blueprint in project/journal_api/__init__.py:

"""
The 'journal_api' blueprint handles the API for managing journal entries.
Specifically, this blueprint allows for journal entries to be added, edited,
and deleted.
"""
from flask import Blueprint

journal_api_blueprint = Blueprint('journal_api', __name__, template_folder='templates')

from . import routes

Now it's time to define the API endpoints for the journal in project/journal_api/routes.py.

Start with the necessary imports:

from apifairy import body, other_responses, response
from flask import abort

from project import ma
from . import journal_api_blueprint

For this initial version of the Flask Journal API, the database will be a list of journal entries:

# --------
# Database
# --------

messages = [
    dict(id=1, entry='The sun was shining when I woke up this morning.'),
    dict(id=2, entry='I tried a new fruit mixture in my oatmeal for breakfast.'),
    dict(id=3, entry='Today I ate a great sandwich for lunch.')
]

Next, define the schemas for creating a new journal entry and for returning the journal entries:

# -------
# Schemas
# -------

class NewEntrySchema(ma.Schema):
    """Schema defining the attributes when creating a new journal entry."""
    entry = ma.String(required=True)


class EntrySchema(ma.Schema):
    """Schema defining the attributes in a journal entry."""
    id = ma.Integer()
    entry = ma.String()


new_entry_schema = NewEntrySchema()
entry_schema = EntrySchema()
entries_schema = EntrySchema(many=True)

Both of these schema classes inherit from ma.Schema, which is provided by Flask-Marshmallow. It's also a good idea to create objects of these schemas, as this allows you to define a schema that can return multiple entries (using the many=True argument).

Now we're ready to define the API endpoints!

Routes

Start with retrieving all the journal entries:

@journal_api_blueprint.route('/', methods=['GET'])
@response(entries_schema)
def journal():
    """Return all journal entries"""
    return messages

This view function uses the @response decorator to define that multiple entries are returned. The view function returns the full list of journal entries (return messages).

Next, create the API endpoint for adding a new journal entry:

@journal_api_blueprint.route('/', methods=['POST'])
@body(new_entry_schema)
@response(entry_schema, 201)
def add_journal_entry(kwargs):
    """Add a new journal entry"""
    new_message = dict(**kwargs, id=messages[-1]['id']+1)
    messages.append(new_message)
    return new_message

This view function uses the @body decorator to define the input to the API endpoint and the @response decorator to define the output from the API endpoint.

The input data that is parsed from the @body decorator is passed into the add_journal_entry() view function as the kwargs (key word arguments) argument. This data is then used to create a new journal entry and add it to the database:

new_message = dict(**kwargs, id=messages[-1]['id']+1)
messages.append(new_message)

The newly created journal entry is then returned (return new_message). Notice how the @response decorator defines the return code as 201 (Created) to indicate that the journal entry was added to the database.

Create the API endpoint for retrieving a specific journal entry:

@journal_api_blueprint.route('/<int:index>', methods=['GET'])
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def get_journal_entry(index):
    """Return a journal entry"""
    if index >= len(messages):
        abort(404)

    return messages[index]

This view function uses the @other_responses decorator to specify non-standard responses.

The @other_responses decorator is only used for documentation purposes! It does not provide any functionality in terms of returning error codes.

Tạo điểm cuối API để cập nhật mục nhập tạp chí:

@journal_api_blueprint.route('/<int:index>', methods=['PUT'])
@body(new_entry_schema)
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def update_journal_entry(data, index):
    """Update a journal entry"""
    if index >= len(messages):
        abort(404)

    messages[index] = dict(data, id=index+1)
    return messages[index]

Hàm dạng xem này sử dụng bộ trang trí @bodyvà bộ @responsetrang trí để xác định các đầu vào và đầu ra (tương ứng) cho điểm cuối API này. Ngoài ra, người @other_responsestrang trí xác định phản hồi không chuẩn nếu mục nhập nhật ký không được tìm thấy.

Cuối cùng, tạo điểm cuối API để xóa mục nhập tạp chí:

@journal_api_blueprint.route('/<int:index>', methods=['DELETE'])
@other_responses({404: 'Entry not found'})
def delete_journal_entry(index):
    """Delete a journal entry"""
    if index >= len(messages):
        abort(404)

    messages.pop(index)
    return '', 204

Hàm xem này không sử dụng @body@responsedecorator, vì không có đầu vào hoặc đầu ra cho điểm cuối API này. Nếu mục nhật ký được xóa thành công, thì mã trạng thái 204 (Không có Nội dung) sẽ được trả về mà không có dữ liệu.

Chạy ứng dụng bình

Để kiểm tra mọi thứ, trong một cửa sổ đầu cuối, hãy định cấu hình ứng dụng Flask và chạy máy chủ phát triển:

(venv) $ export FLASK_APP=app.py
(venv) $ export FLASK_ENV=development
(venv) $ flask run

Sau đó, trong một cửa sổ đầu cuối khác, bạn có thể tương tác với API. Hãy thoải mái sử dụng công cụ bạn chọn tại đây, như cURL, HTTPie , Yêu cầu hoặc Người đưa thư .

Ví dụ về yêu cầu:

$ python3

>>> import requests
>>>
>>> r = requests.get('http://127.0.0.1:5000/journal/')
>>> print(r.text)
>>>
>>> post_data = {'entry': "some message"}
>>> r = requests.post('http://127.0.0.1:5000/journal/', json=post_data)
>>> print(r.text)

Bạn muốn kiểm tra các điểm cuối API dễ dàng hơn? Hãy xem tập lệnh này , tập lệnh này bổ sung các lệnh CLI để tương tác với các điểm cuối API để truy xuất, tạo, cập nhật và xóa các mục nhật ký.

Tài liệu

Một tính năng đáng kinh ngạc của APIFairy là tạo tài liệu API tự động!

Có ba khía cạnh chính để định cấu hình tài liệu API:

  1. Các chuỗi tài liệu cho các điểm cuối API (tức là các hàm xem)
  2. Chuỗi tài liệu cho dự án API tổng thể
  3. Các biến cấu hình để chỉ định giao diện của tài liệu API

We already covered the first item in the previous section since we included the docstrings for each view function. For example, the journal() view function has a short description of the purpose of this API endpoint:

@journal_api_blueprint.route('/', methods=['GET'])
@response(entries_schema)
def journal():
    """Return all journal entries"""
    return messages

Next, we need to include the docstring to describe the overall project at the very top of the project/__init__.py file:

"""
Welcome to the documentation for the Flask Journal API!

## Introduction

The Flask Journal API is an API (Application Programming Interface) for creating a **daily journal** that documents events that happen each day.

## Key Functionality

The Flask Journal API has the following functionality:

1. Work with journal entries:
  * Create a new journal entry
  * Update a journal entry
  * Delete a journal entry
  * View all journal entries
2. <More to come!>

## Key Modules

This project is written using Python 3.10.1.

The project utilizes the following modules:

* **Flask**: micro-framework for web application development which includes the following dependencies:
  * **click**: package for creating command-line interfaces (CLI)
  * **itsdangerous**: cryptographically sign data
  * **Jinja2**: templating engine
  * **MarkupSafe**: escapes characters so text is safe to use in HTML and XML
  * **Werkzeug**: set of utilities for creating a Python application that can talk to a WSGI server
* **APIFairy**: API framework for Flask which includes the following dependencies:
  * **Flask-Marshmallow** - Flask extension for using Marshmallow (object serialization/deserialization library)
  * **Flask-HTTPAuth** - Flask extension for HTTP authentication
  * **apispec** - API specification generator that supports the OpenAPI specification
* **pytest**: framework for testing Python projects
"""
...

This docstring is used to describe the overall project, including the key functionality provided and the key Python packages used by the project.

Finally, some configuration variables need to be defined to specify the look of the API documentation. Update the create_app() function in project/__init__.py:

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    # Configure the API documentation
    app.config['APIFAIRY_TITLE'] = 'Flask Journal API'
    app.config['APIFAIRY_VERSION'] = '0.1'
    app.config['APIFAIRY_UI'] = 'elements'

    initialize_extensions(app)
    register_blueprints(app)

    return app

Sẵn sàng để xem tài liệu cho dự án? Khởi động máy chủ phát triển Flask qua flask run, sau đó điều hướng đến http://127.0.0.1:5000/docs để xem tài liệu API được tạo bởi APIFairy:

Tài liệu API - Trang chính

Trên ngăn bên trái, có một danh sách các điểm cuối API cho journal_apibản thiết kế. Nhấp vào một trong các điểm cuối sẽ hiển thị tất cả thông tin chi tiết về điểm cuối đó:

Tài liệu API - Nhận điểm cuối API mục nhập nhật ký

Điều đáng ngạc nhiên về tài liệu API này là khả năng xem các điểm cuối API hoạt động như thế nào (giả sử máy chủ phát triển Flask đang chạy). Trên ngăn bên phải của tài liệu, nhập chỉ mục mục nhập tạp chí và nhấp vào "Gửi yêu cầu API". Phản hồi API sau đó được hiển thị:

Tài liệu API - Nhận phản hồi API mục nhập nhật ký

Tài liệu tương tác này giúp người dùng dễ dàng hiểu API!

Cơ sở dữ liệu

Đối với mục đích trình diễn, cơ sở dữ liệu SQLite sẽ được sử dụng trong hướng dẫn này.

Cấu hình

Flask-SQLAlchemy đã được cài đặt ở phần đầu của hướng dẫn này, chúng tôi cần phải định cấu hình nó trong tệp dự án / __ init__.py .

Bắt đầu bằng cách tạo một SQLAlchemy()đối tượng trong phần 'Cấu hình':

...

from apifairy import APIFairy
from flask import Flask, json
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy  # <-- NEW!!


# -------------
# Configuration
# -------------

# Create the instances of the Flask extensions in the global scope,
# but without any arguments passed in. These instances are not
# attached to the Flask application at this point.
apifairy = APIFairy()
ma = Marshmallow()
database = SQLAlchemy()  # <-- NEW!!

...

Tiếp theo, cập nhật create_app()hàm để chỉ định các biến cấu hình cần thiết:

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    # Configure the API documentation
    app.config['APIFAIRY_TITLE'] = 'Flask Journal API'
    app.config['APIFAIRY_VERSION'] = '0.1'
    app.config['APIFAIRY_UI'] = 'elements'

    # NEW!
    # Configure the SQLite database (intended for development only!)
    app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{os.path.join(os.getcwd(), 'instance', 'app.db')}"
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    initialize_extensions(app)
    register_blueprints(app)

    return app

Thêm nhập vào đầu:

import os

Biến SQLALCHEMY_DATABASE_URIcấu hình rất quan trọng để xác định vị trí của cơ sở dữ liệu SQLite. Đối với hướng dẫn này, cơ sở dữ liệu được lưu trữ trong instance / app.db.

Cuối cùng, cập nhật initialize_extensions()hàm để khởi tạo đối tượng Flask-SQLAlchemy:

def initialize_extensions(app):
    # Since the application instance is now created, pass it to each Flask
    # extension instance to bind it to the Flask application instance (app)
    apifairy.init_app(app)
    ma.init_app(app)
    database.init_app(app)  # <-- NEW!!

Bạn muốn tìm hiểu thêm về cách kết nối ứng dụng Flask này với nhau? Xem khóa học của tôi về cách xây dựng, kiểm tra và triển khai ứng dụng Flask:

Mô hình cơ sở dữ liệu

Tạo một tệp project / models.py mới để xác định bảng cơ sở dữ liệu đại diện cho các mục nhật ký:

from project import database


class Entry(database.Model):
    """Class that represents a journal entry."""
    __tablename__ = 'entries'

    id = database.Column(database.Integer, primary_key=True)
    entry = database.Column(database.String, nullable=False)

    def __init__(self, entry: str):
        self.entry = entry

    def update(self, entry: str):
        self.entry = entry

    def __repr__(self):
        return f'<Entry: {self.entry}>'

Lớp mới này Entry, chỉ định rằng entriesbảng cơ sở dữ liệu sẽ chứa hai phần tử (hiện tại!) Để đại diện cho một mục nhập nhật ký:

  1. id- khóa chính ( primary_key=True) cho bảng, có nghĩa là đó là mã định danh duy nhất cho mỗi phần tử (hàng) trong bảng
  2. entry- chuỗi để lưu trữ văn bản nhập nhật ký

Trong khi models.py định nghĩa bảng cơ sở dữ liệu, nó không tạo các bảng trong cơ sở dữ liệu SQLite. Để tạo bảng, hãy khởi động trình bao Flask trong cửa sổ dòng lệnh:

(venv)$ flask shell

>>> from project import database
>>> database.drop_all()
>>> database.create_all()
>>> quit()

(venv)$

Cập nhật API tạp chí

Vì chúng tôi đang tiến hành sử dụng cơ sở dữ liệu SQLite, hãy bắt đầu bằng cách xóa tạm thời database(danh sách Python) đã được xác định trong project / journal_api / route.py :

# --------
# Database
# --------

messages = [
    dict(id=1, entry='The sun was shining when I woke up this morning.'),
    dict(id=2, entry='I tried a new fruit mixture in my oatmeal for breakfast.'),
    dict(id=3, entry='Today I ate a great sandwich for lunch.')
]

Tiếp theo, chúng ta cần cập nhật từng điểm cuối API (tức là các chức năng dạng xem) để sử dụng cơ sở dữ liệu SQLite.

Bắt đầu bằng cách cập nhật journal()chức năng xem:

@journal_api_blueprint.route('/', methods=['GET'])
@response(entries_schema)
def journal():
    """Return all journal entries"""
    return Entry.query.all()

Danh sách đầy đủ các mục nhật ký hiện được truy xuất từ ​​cơ sở dữ liệu SQLite. Lưu ý rằng các lược đồ hoặc trình trang trí cho chức năng xem này không cần thay đổi như thế nào ... chỉ có quy trình cơ bản để thay đổi người dùng!

Thêm nhập khẩu:

from project.models import Entry

Tiếp theo, cập nhật add_journal_entry()chức năng xem:

@journal_api_blueprint.route('/', methods=['POST'])
@body(new_entry_schema)
@response(entry_schema, 201)
def add_journal_entry(kwargs):
    """Add a new journal entry"""
    new_message = Entry(**kwargs)
    database.session.add(new_message)
    database.session.commit()
    return new_message

Các đầu vào cho chức năng xem này được chỉ định bởi new_entry_schema:

class NewEntrySchema(ma.Schema):
    """Schema defining the attributes when creating a new journal entry."""
    entry = ma.String(required=True)

new_entry_schema = NewEntrySchema()

Chuỗi entryđược sử dụng để tạo một phiên bản mới của Entrylớp (được định nghĩa trong models.py ) và mục nhật ký này sau đó được thêm vào cơ sở dữ liệu.

Thêm nhập khẩu:

from project import database

Tiếp theo, cập nhật get_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['GET'])
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def get_journal_entry(index):
    """Return a journal entry"""
    entry = Entry.query.filter_by(id=index).first_or_404()
    return entry

Chức năng này hiện cố gắng tra cứu mục nhập nhật ký được chỉ định (dựa trên index):

entry = Entry.query.filter_by(id=index).first_or_404()

Nếu mục nhập tồn tại, nó sẽ được trả lại cho người dùng. Nếu mục nhập không tồn tại, lỗi 404 (Không tìm thấy) sẽ được trả về.

Tiếp theo, cập nhật update_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['PUT'])
@body(new_entry_schema)
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def update_journal_entry(data, index):
    """Update a journal entry"""
    entry = Entry.query.filter_by(id=index).first_or_404()
    entry.update(data['entry'])
    database.session.add(entry)
    database.session.commit()
    return entry

Chức update_journal_entry()năng xem bây giờ cố gắng truy xuất mục nhập nhật ký được chỉ định:

entry = Entry.query.filter_by(id=index).first_or_404()

Nếu mục nhật ký tồn tại, mục đó được cập nhật văn bản mới và sau đó được lưu vào cơ sở dữ liệu.

Cuối cùng, hãy cập nhật delete_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['DELETE'])
@other_responses({404: 'Entry not found'})
def delete_journal_entry(index):
    """Delete a journal entry"""
    entry = Entry.query.filter_by(id=index).first_or_404()
    database.session.delete(entry)
    database.session.commit()
    return '', 204

Nếu mục nhật ký được chỉ định được tìm thấy, thì nó sẽ bị xóa khỏi cơ sở dữ liệu.

Chạy máy chủ phát triển. Kiểm tra từng điểm cuối để đảm bảo chúng vẫn hoạt động.

Xử lý lỗi

Vì dự án Flask này là một API, mã lỗi phải được trả về ở định dạng JSON thay vì định dạng HTML điển hình.

Trong dự án Flask, điều này có thể được thực hiện bằng cách sử dụng trình xử lý lỗi tùy chỉnh. Trong project / __ init__.py , hãy xác định một hàm mới ( register_error_handlers()) ở cuối tệp:

def register_error_handlers(app):
    @app.errorhandler(HTTPException)
    def handle_http_exception(e):
        """Return JSON instead of HTML for HTTP errors."""
        # Start with the correct headers and status code from the error
        response = e.get_response()
        # Replace the body with JSON
        response.data = json.dumps({
            'code': e.code,
            'name': e.name,
            'description': e.description,
        })
        response.content_type = 'application/json'
        return response

Hàm này đăng ký một trình xử lý lỗi mới khi một HTTPExceptionđược nâng lên để chuyển đổi đầu ra thành định dạng JSON.

Thêm nhập khẩu:

from werkzeug.exceptions import HTTPException

Ngoài ra, hãy cập nhật chức năng Nhà máy ứng dụng create_app(), để gọi chức năng mới này:

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    # Configure the API documentation
    app.config['APIFAIRY_TITLE'] = 'Flask Journal API'
    app.config['APIFAIRY_VERSION'] = '0.1'
    app.config['APIFAIRY_UI'] = 'elements'

    # Configure the SQLite database (intended for development only!)
    app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{os.path.join(os.getcwd(), 'instance', 'app.db')}"
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    initialize_extensions(app)
    register_blueprints(app)
    register_error_handlers(app)  # NEW!!

    return app

Xác thực

Authentication is the process of validating the identity of a user attempting to access a system, which in this case is the API.

Authorization, on the other hand, is the process of verifying what specific resources a specific user should have access to.

APIFairy utilizes Flask-HTTPAuth for authentication support. In this tutorial, we'll be using Flask-HTTPAuth in two manners:

  1. Basic Authentication - used to generate a token based on the user's email/password
  2. Token Authentication - used to authenticate the user on all other API endpoints

Xác thực mã thông báo được sử dụng qua Flask-HTTPAuth thường được gọi là Xác thực mang, vì quá trình này yêu cầu cấp quyền truy cập cho "người mang" mã thông báo. Mã thông báo phải được bao gồm trong tiêu đề HTTP trong tiêu đề Ủy quyền, chẳng hạn như "Ủy quyền: Người mang".

Sơ đồ sau minh họa một quy trình điển hình về cách người dùng mới tương tác với ứng dụng để truy xuất mã thông báo xác thực:

Sơ đồ luồng API của tạp chí Flask

Cấu hình

Vì Flask-HTTPAuth đã được cài đặt khi APIFairy được cài đặt ở phần đầu của hướng dẫn này, chúng tôi chỉ cần định cấu hình nó trong tệp dự án / __ init__.py .

Bắt đầu bằng cách tạo các đối tượng riêng biệt để xác thực mã thông báo và cơ bản:

...

import os

from apifairy import APIFairy
from flask import Flask, json
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth  # NEW!!
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from werkzeug.exceptions import HTTPException


# -------------
# Configuration
# -------------

# Create the instances of the Flask extensions in the global scope,
# but without any arguments passed in. These instances are not
# attached to the Flask application at this point.
apifairy = APIFairy()
ma = Marshmallow()
database = SQLAlchemy()
basic_auth = HTTPBasicAuth()  # NEW!!
token_auth = HTTPTokenAuth()  # NEW!!

...

Không cần cập nhật thêm trong dự án / __ init__.py .

Mô hình cơ sở dữ liệu

Trong project / models.py , một Usermô hình mới cần được tạo để đại diện cho người dùng:

class User(database.Model):
    __tablename__ = 'users'

    id = database.Column(database.Integer, primary_key=True)
    email = database.Column(database.String, unique=True, nullable=False)
    password_hashed = database.Column(database.String(128), nullable=False)
    entries = database.relationship('Entry', backref='user', lazy='dynamic')
    auth_token = database.Column(database.String(64), index=True)
    auth_token_expiration = database.Column(database.DateTime)

    def __init__(self, email: str, password_plaintext: str):
        """Create a new User object."""
        self.email = email
        self.password_hashed = self._generate_password_hash(password_plaintext)

    def is_password_correct(self, password_plaintext: str):
        return check_password_hash(self.password_hashed, password_plaintext)

    def set_password(self, password_plaintext: str):
        self.password_hashed = self._generate_password_hash(password_plaintext)

    @staticmethod
    def _generate_password_hash(password_plaintext):
        return generate_password_hash(password_plaintext)

    def generate_auth_token(self):
        self.auth_token = secrets.token_urlsafe()
        self.auth_token_expiration = datetime.utcnow() + timedelta(minutes=60)
        return self.auth_token

    @staticmethod
    def verify_auth_token(auth_token):
        user = User.query.filter_by(auth_token=auth_token).first()
        if user and user.auth_token_expiration > datetime.utcnow():
            return user

    def revoke_auth_token(self):
        self.auth_token_expiration = datetime.utcnow()

    def __repr__(self):
        return f'<User: {self.email}>'

Thêm nhập khẩu:

import secrets
from datetime import datetime, timedelta

from werkzeug.security import check_password_hash, generate_password_hash

Userhình sử dụng werkzeug.securityđể băm mật khẩu của người dùng trước khi lưu trữ trong cơ sở dữ liệu.

Hãy nhớ: Không bao giờ lưu trữ mật khẩu văn bản rõ trong cơ sở dữ liệu!

Userhình sử dụng secretsđể tạo mã thông báo xác thực cho một người dùng cụ thể. Mã thông báo này được tạo trong generate_auth_token()phương thức và bao gồm ngày / giờ hết hạn là 60 phút trong tương lai:

def generate_auth_token(self):
    self.auth_token = secrets.token_urlsafe()
    self.auth_token_expiration = datetime.utcnow() + timedelta(minutes=60)
    return self.auth_token

Có một phương thức tĩnh, verify_auth_token()được sử dụng để xác minh mã thông báo xác thực (trong khi xem xét thời gian hết hạn) và trả lại người dùng từ mã thông báo hợp lệ:

@staticmethod
def verify_auth_token(auth_token):
    user = User.query.filter_by(auth_token=auth_token).first()
    if user and user.auth_token_expiration > datetime.utcnow():
        return user

Một phương pháp quan tâm khác là revoke_auth_token(), được sử dụng để thu hồi mã thông báo xác thực cho một người dùng cụ thể:

def revoke_auth_token(self):
    self.auth_token_expiration = datetime.utcnow()

Mô hình nhập cảnh

Để thiết lập mối quan hệ một-nhiều giữa người dùng ("một") và các mục nhập của họ ("nhiều"), Entrymô hình cần được cập nhật để liên kết các bảng entriesusersvới nhau:

class Entry(database.Model):
    """Class that represents a journal entry."""
    __tablename__ = 'entries'

    id = database.Column(database.Integer, primary_key=True)
    entry = database.Column(database.String, nullable=False)
    user_id = database.Column(database.Integer, database.ForeignKey('users.id'))  # <-- NEW!!

    def __init__(self, entry: str):
        self.entry = entry

    def update(self, entry: str):
        self.entry = entry

    def __repr__(self):
        return f'<Entry: {self.entry}>'

Userhình đã chứa liên kết quay lại entriesbảng:

entries = database.relationship('Entry', backref='user', lazy='dynamic')

Bản thiết kế API người dùng

Chức năng quản lý người dùng của dự án Flask sẽ được định nghĩa trong một Bản thiết kế riêng được gọi là users_api_blueprint.

Bắt đầu bằng cách tạo một thư mục mới trong "dự án" được gọi là "users_api". Trong thư mục đó, hãy tạo một tệp __init__.py :

from flask import Blueprint


users_api_blueprint = Blueprint('users_api', __name__)

from . import authentication, routes

Bản kế hoạch chi tiết mới này cần được đăng ký với Flask apptrong các dự án / __ init__.py trong register_blueprints()hàm:

def register_blueprints(app):
    # Import the blueprints
    from project.journal_api import journal_api_blueprint
    from project.users_api import users_api_blueprint  # NEW!!

    # Since the application instance is now created, register each Blueprint
    # with the Flask application instance (app)
    app.register_blueprint(journal_api_blueprint, url_prefix='/journal')
    app.register_blueprint(users_api_blueprint, url_prefix='/users')  # NEW!!

Chức năng xác thực

Để sử dụng Flask-HTTPAuth, một số chức năng cần được xác định để xử lý việc kiểm tra thông tin đăng nhập của người dùng.

Tạo một tệp dự án / users_api / verify.py mới để xử lý xác thực cơ bản và xác thực mã thông báo.

Đối với xác thực cơ bản (kiểm tra email và mật khẩu của người dùng):

from werkzeug.exceptions import Forbidden, Unauthorized

from project import basic_auth, token_auth
from project.models import User


@basic_auth.verify_password
def verify_password(email, password):
    user = User.query.filter_by(email=email).first()
    if user is None:
        return None

    if user.is_password_correct(password):
        return user


@basic_auth.error_handler
def basic_auth_error(status=401):
    error = (Forbidden if status == 403 else Unauthorized)()
    return {
        'code': error.code,
        'message': error.name,
        'description': error.description,
    }, error.code, {'WWW-Authenticate': 'Form'}

Hàm verify_password()được sử dụng để kiểm tra xem người dùng có tồn tại và mật khẩu của họ có chính xác hay không. Chức năng này sẽ được sử dụng bởi Flask-HTTPAuth để xác minh mật khẩu khi cần xác thực cơ bản (nhờ trình @basic_auth.verify_passwordtrang trí).

Ngoài ra, một trình xử lý lỗi được xác định cho xác thực cơ bản trả về thông tin về lỗi ở định dạng JSON.

Đối với xác thực mã thông báo (xử lý mã thông báo để xác định xem người dùng có hợp lệ hay không):

@token_auth.verify_token
def verify_token(auth_token):
    return User.verify_auth_token(auth_token)


@token_auth.error_handler
def token_auth_error(status=401):
    error = (Forbidden if status == 403 else Unauthorized)()
    return {
        'code': error.code,
        'message': error.name,
        'description': error.description,
    }, error.code

Hàm verify_token()được sử dụng để kiểm tra xem mã thông báo xác thực có hợp lệ hay không. Chức năng này sẽ được sử dụng bởi Flask-HTTPAuth để xác minh mã thông báo khi cần xác thực mã thông báo (nhờ trình @token_auth.verify_tokentrang trí).

Ngoài ra, một trình xử lý lỗi được xác định để xác thực mã thông báo trả về thông tin về lỗi ở định dạng JSON.

Các tuyến đường của người dùng

Trong users_api_blueprint, sẽ có hai tuyến đường:

  1. Đăng ký người dùng mới
  2. Truy xuất mã thông báo xác thực

Để bắt đầu, một tập hợp các lược đồ mới (sử dụng marshmallow) cần được xác định trong các dự án / users_api / route.py :

from project import ma

from . import users_api_blueprint

# -------
# Schemas
# -------

class NewUserSchema(ma.Schema):
    """Schema defining the attributes when creating a new user."""
    email = ma.String()
    password_plaintext = ma.String()


class UserSchema(ma.Schema):
    """Schema defining the attributes of a user."""
    id = ma.Integer()
    email = ma.String()


class TokenSchema(ma.Schema):
    """Schema defining the attributes of a token."""
    token = ma.String()


new_user_schema = NewUserSchema()
user_schema = UserSchema()
token_schema = TokenSchema()

Các lược đồ này sẽ được sử dụng để xác định các đầu vào và đầu ra cho các chức năng dạng xem được xác định trong tệp này.

Đăng ký người dùng mới

Tiếp theo, xác định chức năng xem để đăng ký người dùng mới:

@users_api_blueprint.route('/', methods=['POST'])
@body(new_user_schema)
@response(user_schema, 201)
def register(kwargs):
    """Create a new user"""
    new_user = User(**kwargs)
    database.session.add(new_user)
    database.session.commit()
    return new_user

Thêm nhập khẩu:

from apifairy import authenticate, body, other_responses, response

from project import basic_auth, database, ma
from project.models import User

Điểm cuối API này sử dụng new_user_schemađể chỉ định rằng email và mật khẩu là đầu vào.

LƯU Ý: Vì email và mật khẩu được gửi đến điểm cuối API này, nên nhớ rằng việc sử dụng HTTP được chấp nhận trong quá trình thử nghiệm phát triển, nhưng HTTPS (bảo mật) phải luôn được sử dụng trong quá trình sản xuất.

Sau đó, email và mật khẩu (được định nghĩa là kwargsđối số - từ khóa) được giải nén để tạo một Userđối tượng mới, được lưu vào cơ sở dữ liệu:

new_user = User(**kwargs)
database.session.add(new_user)
database.session.commit()

Đầu ra từ điểm cuối API được xác định bởi user_schema, đó là ID và email cho người dùng mới.

Truy xuất mã thông báo xác thực

Chức năng xem khác để xác định trong các dự án / users_api / route.py là để truy xuất mã thông báo xác thực:

@users_api_blueprint.route('/get-auth-token', methods=['POST'])
@authenticate(basic_auth)
@response(token_schema)
@other_responses({401: 'Invalid username or password'})
def get_auth_token():
    """Get authentication token"""
    user = basic_auth.current_user()
    token = user.generate_auth_token()
    database.session.add(user)
    database.session.commit()
    return dict(token=token)

Trình @authenticatetrang trí được sử dụng lần đầu tiên trong hướng dẫn này và nó chỉ định rằng xác thực cơ bản nên được sử dụng để bảo vệ tuyến đường này:

@authenticate(basic_auth)

Khi người dùng muốn truy xuất mã thông báo xác thực của họ, họ cần gửi yêu cầu ĐĂNG tới điểm cuối API này với email và mật khẩu được nhúng trong tiêu đề 'Ủy quyền'. Ví dụ: lệnh Python sau sử dụng gói Yêu cầu có thể được thực hiện cho điểm cuối API này:

>>> import requests
>>> r = requests.post(
    'http://127.0.0.1:5000/users/get-auth-token',
    auth=('pkennedy@hey.com', 'FlaskIsAwesome123')
)

Nếu xác thực cơ bản thành công, chức năng xem sẽ truy xuất người dùng hiện tại bằng current_user()phương pháp được cung cấp bởi Flask-HTTPAuth:

user = basic_auth.current_user()

Mã thông báo xác thực mới được tạo cho người dùng đó:

token = user.generate_auth_token()

Và mã thông báo đó được lưu vào cơ sở dữ liệu để nó có thể được sử dụng để xác thực người dùng trong tương lai (ít nhất là trong 60 phút tới!).

Cuối cùng, mã thông báo xác thực mới được trả lại để người dùng lưu cho tất cả các lệnh gọi API tiếp theo.

Cập nhật điểm cuối API

Với quy trình xác thực đã có, đã đến lúc thêm một số bảo vệ vào các điểm cuối API hiện có để đảm bảo rằng chỉ những người dùng hợp lệ mới có thể truy cập ứng dụng.

Các cập nhật này dành cho các chức năng xem được xác định trong các dự án / journal_api / route.py .

Đầu tiên, hãy cập nhật journal()để chỉ trả lại các mục nhật ký cho người dùng hiện tại:

@journal_api_blueprint.route('/', methods=['GET'])
@authenticate(token_auth)
@response(entries_schema)
def journal():
    """Return journal entries"""
    user = token_auth.current_user()
    return Entry.query.filter_by(user_id=user.id).all()

Cập nhật các nhập ở trên cùng như sau:

from apifairy import authenticate, body, other_responses, response
from flask import abort

from project import database, ma, token_auth
from project.models import Entry

from . import journal_api_blueprint

Người @authenticatetrang trí chỉ định rằng xác thực mã thông báo cần được sử dụng khi truy cập điểm cuối API này. Ví dụ: yêu cầu GET sau có thể được thực hiện bằng Yêu cầu ( sau khi mã thông báo xác thực đã được truy xuất ):

>>> import requests
>>> headers = {'Authorization': f'Bearer {auth_token}'}
>>> r = requests.get('http://127.0.0.1:5000/journal/', headers=headers)

Sau khi người dùng được xác thực, danh sách đầy đủ các mục nhật ký sẽ được truy xuất từ ​​cơ sở dữ liệu dựa trên ID của người dùng:

user = token_auth.current_user()
return Entry.query.filter_by(user_id=user.id).all()

Đầu ra từ điểm cuối API này được xác định bởi người @responsetrang trí, là danh sách các mục nhật ký (ID, mục nhập, ID người dùng).

Tiếp theo, cập nhật add_journal_entry():

@journal_api_blueprint.route('/', methods=['POST'])
@authenticate(token_auth)
@body(new_entry_schema)
@response(entry_schema, 201)
def add_journal_entry(kwargs):
    """Add a new journal entry"""
    user = token_auth.current_user()
    new_message = Entry(user_id=user.id, **kwargs)
    database.session.add(new_message)
    database.session.commit()
    return new_message

Như với chức năng xem trước, trình @authenticatetrang trí được sử dụng để chỉ định rằng xác thực mã thông báo cần được sử dụng khi truy cập điểm cuối API này. Ngoài ra, mục nhập tạp chí hiện được thêm vào bằng cách chỉ định ID người dùng sẽ được liên kết với mục nhập tạp chí:

user = token_auth.current_user()
new_message = Entry(user_id=user.id, **kwargs)

Mục nhật ký mới được lưu vào cơ sở dữ liệu và mục nhập nhật ký được trả lại (theo định nghĩa của người @responsetrang trí).

Tiếp theo, cập nhật get_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['GET'])
@authenticate(token_auth)
@response(entry_schema)
@other_responses({403: 'Forbidden', 404: 'Entry not found'})
def get_journal_entry(index):
    """Return a journal entry"""
    user = token_auth.current_user()
    entry = Entry.query.filter_by(id=index).first_or_404()

    if entry.user_id != user.id:
        abort(403)
    return entry

Trình @authenticatetrang trí được thêm vào để chỉ định rằng cần xác thực mã thông báo để truy cập điểm cuối API này.

Khi cố gắng truy xuất mục nhập nhật ký, một kiểm tra bổ sung được thêm vào để đảm bảo rằng người dùng cố gắng truy cập mục nhập nhật ký là "chủ sở hữu" thực sự của mục nhập. Nếu không, thì mã lỗi 403 (Bị cấm) được trả về thông qua abort()hàm từ Flask:

if entry.user_id != user.id:
        abort(403)

Hãy lưu ý rằng điểm cuối API này có hai phản hồi ngoài danh nghĩa được chỉ định bởi người @other_responsestrang trí:

@other_responses({403: 'Forbidden', 404: 'Entry not found'})

Nhắc nhở: Trình @other_responsestrang trí chỉ dành cho tài liệu; đó là trách nhiệm của chức năng xem để tạo ra những lỗi này.

Tiếp theo, cập nhật update_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['PUT'])
@authenticate(token_auth)
@body(new_entry_schema)
@response(entry_schema)
@other_responses({403: 'Forbidden', 404: 'Entry not found'})
def update_journal_entry(data, index):
    """Update a journal entry"""
    user = token_auth.current_user()
    entry = Entry.query.filter_by(id=index).first_or_404()

    if entry.user_id != user.id:
        abort(403)

    entry.update(data['entry'])
    database.session.add(entry)
    database.session.commit()
    return entry

Các cập nhật cho chức năng xem này tương tự như các chức năng xem khác trong phần này:

  1. @authenticatedecorator chỉ định rằng xác thực mã thông báo là cần thiết để truy cập điểm cuối API này
  2. Chỉ người dùng "sở hữu" mục nhập mới được phép cập nhật mục nhập (nếu không, 403 (Bị cấm))

Cuối cùng, hãy cập nhật delete_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['DELETE'])
@authenticate(token_auth)
@other_responses({403: 'Forbidden', 404: 'Entry not found'})
def delete_journal_entry(index):
    """Delete a journal entry"""
    user = token_auth.current_user()
    entry = Entry.query.filter_by(id=index).first_or_404()

    if entry.user_id != user.id:
        abort(403)

    database.session.delete(entry)
    database.session.commit()
    return '', 204

Sự kết luận

Hướng dẫn này đã cung cấp hướng dẫn về cách dễ dàng và nhanh chóng xây dựng một API trong Flask bằng APIFairy.

Trình trang trí là chìa khóa để xác định các điểm cuối API:

  • Đầu vào :
    • @arguments- đầu vào đối số từ chuỗi truy vấn của URL
    • @body- cấu trúc của yêu cầu JSON
  • Kết quả đầu ra :
    • @response- cấu trúc của phản hồi JSON
  • Xác thực :
    • @authenticate- phương pháp xác thực sử dụng Flask-HTTPAuth
  • Các lỗi :
    • @other_responses- phản hồi ngoài danh nghĩa, chẳng hạn như mã lỗi HTTP

Thêm vào đó, tài liệu API do APIFairy tạo ra rất tuyệt vời và cung cấp thông tin chính cho người dùng ứng dụng.

Nguồn:  https://testdriven.io

#api #flask