
Python實(shí)現(xiàn)動圖生成:輕松創(chuàng)建自定義表情包
在本示例中,API 定義了多個用于管理圖書的端點(diǎn)(路由)。每個端點(diǎn)都允許客戶對圖書資源執(zhí)行特定操作。
端點(diǎn)是提供特定服務(wù)的特定 URL 模式。它代表通信通道的一端,通常與應(yīng)用程序接口公開的操作相對應(yīng)。
端點(diǎn)是應(yīng)用程序接口的重要組成部分。它們定義了訪問或操作資源的位置和方式。
繼續(xù)前面的例子,讓我們來確定端點(diǎn):
GET /books:獲取所有書籍的列表。
POST /books:添加新書
PUT /books/<int:id>: 用指定的 ID 更新圖書。
DELETE /books/<int:id>: 刪除指定 ID 的圖書。
每個端點(diǎn)都執(zhí)行不同的操作,允許客戶以特定方式與圖書資源交互。
為了進(jìn)一步說明應(yīng)用程序接口和端點(diǎn)之間的區(qū)別和互動,讓我們擴(kuò)展前面的示例。我們將添加更多的功能,并展示端點(diǎn)如何在更廣泛的 API 環(huán)境中工作。
讓我們?yōu)閼?yīng)用程序接口添加身份驗(yàn)證。只有通過身份驗(yàn)證的用戶才能添加、更新或刪除圖書。
from flask import Flask, jsonify, request, abort
app = Flask(__name__)
books = [
{'id': 1, 'title': '1984', 'author': 'George Orwell'},
{'id': 2, 'title': 'To Kill a Mockingbird', 'author': 'Harper Lee'}
]
users = {
'user1': 'password1',
'user2': 'password2'
}
def authenticate():
auth = request.authorization
if not auth or not users.get(auth.username) == auth.password:
return False
return True
@app.route('/books', methods=['GET'])
def get_books():
return jsonify(books)
@app.route('/books', methods=['POST'])
def add_book():
if not authenticate():
return jsonify({'error': 'Unauthorized access'}), 401
new_book = request.get_json()
books.append(new_book)
return jsonify(new_book), 201
@app.route('/books/<int:id>', methods=['PUT'])
def update_book(id):
if not authenticate():
return jsonify({'error': 'Unauthorized access'}), 401
book = next((b for b in books if b['id'] == id), None)
if book is None:
return jsonify({'error': 'Book not found'}), 404
data = request.get_json()
book.update(data)
return jsonify(book)
@app.route('/books/<int:id>', methods=['DELETE'])
def delete_book(id):
if not authenticate():
return jsonify({'error': 'Unauthorized access'}), 401
global books
books = [b for b in books if b['id'] != id]
return '', 204
if __name__ == '__main__':
app.run(debug=True)
在本例中,驗(yàn)證函數(shù)會檢查請求是否包含有效的驗(yàn)證憑證。POST、PUT 和 DELETE 端點(diǎn)受保護(hù),需要有效憑證才能訪問。
讓我們通過添加更詳細(xì)的錯誤處理來改進(jìn)我們的應(yīng)用程序接口。這樣可以確??蛻粼诔鲥e時收到有意義的錯誤信息。
from flask import Flask, jsonify, request, abort
app = Flask(__name__)
books = [
{'id': 1, 'title': '1984', 'author': 'George Orwell'},
{'id': 2, 'title': 'To Kill a Mockingbird', 'author': 'Harper Lee'}
]
users = {
'user1': 'password1',
'user2': 'password2'
}
def authenticate():
auth = request.authorization
if not auth or not users.get(auth.username) == auth.password:
return False
return True
@app.errorhandler(400)
def bad_request(error):
return jsonify({'error': 'Bad request'}), 400
@app.errorhandler(401)
def unauthorized(error):
return jsonify({'error': 'Unauthorized access'}), 401
@app.errorhandler(404)
def not_found(error):
return jsonify({'error': 'Resource not found'}), 404
@app.route('/books', methods=['GET'])
def get_books():
return jsonify(books)
@app.route('/books', methods=['POST'])
def add_book():
if not authenticate():
abort(401)
if not request.json or not 'title' in request.json:
abort(400)
new_book = {
'id': books[-1]['id'] + 1 if books else 1,
'title': request.json['title'],
'author': request.json.get('author', "")
}
books.append(new_book)
return jsonify(new_book), 201
@app.route('/books/<int:id>', methods=['PUT'])
def update_book(id):
if not authenticate():
abort(401)
book = next((b for b in books if b['id'] == id), None)
if book is None:
abort(404)
if not request.json:
abort(400)
book['title'] = request.json.get('title', book['title'])
book['author'] = request.json.get('author', book['author'])
return jsonify(book)
@app.route('/books/<int:id>', methods=['DELETE'])
def delete_book(id):
if not authenticate():
abort(401)
global books
books = [b for b in books if b['id'] != id]
return '', 204
if __name__ == '__main__':
app.run(debug=True)
在這個改進(jìn)版本中,我們?yōu)椴煌?HTTP 狀態(tài)代碼添加了自定義錯誤處理程序。中止函數(shù)用于在必要時觸發(fā)這些錯誤處理程序,為客戶端提供更多的錯誤信息。
隨著應(yīng)用程序接口的復(fù)雜性不斷增加,管理不同版本和限制請求率以確保穩(wěn)定性和向后兼容性變得至關(guān)重要。
應(yīng)用程序接口版本管理允許您維護(hù)不同版本的應(yīng)用程序接口,以支持傳統(tǒng)客戶端,同時為新客戶端添加新功能。讓我們?yōu)閼?yīng)用程序接口添加版本控制。
from flask import Flask, jsonify, request, abort
app = Flask(__name__)
books_v1 = [
{'id': 1, 'title': '1984', 'author': 'George Orwell'},
{'id': 2, 'title': 'To Kill a Mockingbird', 'author': 'Harper Lee'}
]
books_v2 = [
{'id': 1, 'title': '1984', 'author': 'George Orwell', 'published': '1949'},
{'id': 2, 'title': 'To Kill a Mockingbird', 'author': 'Harper Lee', 'published': '1960'}
]
users = {
'user1': 'password1',
'user2': 'password2'
}
def authenticate():
auth = request.authorization
if not auth or not users.get(auth.username) == auth.password:
return False
return True
@app.route('/v1/books', methods=['GET'])
def get_books_v1():
return jsonify(books_v1)
@app.route('/v1/books', methods=['POST'])
def add_book_v1():
if not authenticate():
abort(401)
if not request.json or not 'title' in request.json:
abort(400)
new_book = {
'id': books_v1[-1]['id'] + 1 if books_v1 else 1,
'title': request.json['title'],
'author': request.json.get('author', "")
}
books_v1.append(new_book)
return jsonify(new_book), 201
@app.route('/v1/books/<int:id>', methods=['PUT'])
def update_book_v1(id):
if not authenticate():
abort(401)
book = next((b for b in books_v1 if b['id'] == id), None)
if book is None:
abort(404)
if not request.json:
abort(400)
book['title'] = request.json.get('title', book['title'])
book['author'] = request.json.get('author', book['author'])
return jsonify(book)
@app.route('/v1/books/<int:id>', methods=['DELETE'])
def delete_book_v1(id):
if not authenticate():
abort(401)
global books_v1
books_v1 = [b for b in books_v1 if b['id'] != id]
return '', 204
@app.route('/v2/books', methods=['GET'])
def get_books_v2():
return jsonify(books_v2)
@app.route('/v2/books', methods=['POST'])
def add_book_v2():
if not authenticate():
abort(401)
if not request.json or not 'title' in request.json:
abort(400)
new_book = {
'id': books_v2[-1]['id'] + 1 if books_v2 else 1,
'title': request.json['title'],
'author': request.json.get('author', ""),
'published': request.json.get('published', "")
}
books_v2.append(new_book)
return jsonify(new_book), 201
@app.route('/v2/books/<int:id>', methods=['PUT'])
def update_book_v2(id):
if not authenticate():
abort(401)
book = next((b for b in books_v2 if b['id'] == id), None)
if book is None:
abort(404)
if not request.json:
abort(400)
book['title'] = request.json.get('title', book['title'])
book['author'] = request.json.get('author', book['author'])
book['published'] = request.json.get('published', book['published'])
return jsonify(book)
@app.route('/v2/books/<int:id>', methods=['DELETE'])
def delete_book_v2(id):
if not authenticate():
abort(401)
global books_v2
books_v2 = [b for b in books_v2 if b['id'] != id]
return '', 204
if __name__ == '__main__':
app.run(debug=True)
在本例中,我們創(chuàng)建了兩個版本的應(yīng)用程序接口(v1 和 v2)。每個版本都有自己的端點(diǎn)集,允許客戶選擇與哪個版本進(jìn)行交互。 這種方法有助于保持向后兼容性,同時又能引入新的功能和改進(jìn)。
速率限制為客戶在一定時間內(nèi)向應(yīng)用程序接口發(fā)出的請求數(shù)量設(shè)置了上限。這樣可以確保客戶端之間的公平使用,防止濫用。讓我們使用 flask-limiter 擴(kuò)展為我們的應(yīng)用程序接口提供速率限制。
from flask import Flask, jsonify, request, abort
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
app = Flask(__name__)
limiter = Limiter(
get_remote_address,
app=app,
default_limits=["200 per day", "50 per hour"]
)
books = [
{'id': 1, 'title': '1984', 'author': 'George Orwell'},
{'id': 2, 'title': 'To Kill a Mockingbird', 'author': 'Harper Lee'}
]
users = {
'user1': 'password1',
'user2': 'password2'
}
def authenticate():
auth = request.authorization
if not auth or not users.get(auth.username) == auth.password:
return False
return True
@app.errorhandler(400)
def bad_request(error):
return jsonify({'error': 'Bad request'}), 400
@app.errorhandler(401)
def unauthorized(error):
return jsonify({'error': 'Unauthorized access'}), 401
@app.errorhandler(404)
def not_found(error):
return jsonify({'error': 'Resource not found'}), 404
@app.errorhandler(429)
def ratelimit_error(error):
return jsonify({'error': 'Too many requests'}), 429
@app.route('/books', methods=['GET'])
@limiter.limit("10 per minute")
def get_books():
return jsonify(books)
@app.route('/books', methods=['POST'])
@limiter.limit("5 per minute")
def add_book():
if not authenticate():
abort(401)
if not request.json or not 'title' in request.json:
abort(400)
new_book = {
'id': books[-1]['id'] + 1 if books else 1,
'title': request.json['title'],
'author': request.json.get('author', "")
}
books.append(new_book)
return jsonify(new_book), 201
@app.route('/books/<int:id>', methods=['PUT'])
@limiter.limit("5 per minute")
def update_book(id):
if not authenticate():
abort(401)
book = next((b for b in books if b['id'] == id), None)
if book is None:
abort(404)
if not request.json:
abort(400)
book['title'] = request.json.get('title', book['title'])
book['author'] = request.json.get('author', book['author'])
return jsonify(book)
@app.route('/books/<int:id>', methods=['DELETE'])
@limiter.limit("5 per minute")
def delete_book(id):
if not authenticate():
abort(401)
global books
books = [b for b in books if b['id'] != id]
return '', 204
if __name__ == '__main__':
app.run(debug=True)
在本例中,flask-limiter 擴(kuò)展用于對不同端點(diǎn)應(yīng)用速率限制。default_limits 參數(shù)設(shè)置了全局速率限制,而 @limiter.limit 裝飾器則為單個端點(diǎn)應(yīng)用了特定的速率限制。 如果客戶端超過了允許的請求數(shù),就會收到 429 請求過多的錯誤信息。
應(yīng)用程序接口(API)和端點(diǎn)是網(wǎng)絡(luò)開發(fā)中的基本概念,各自在實(shí)現(xiàn)軟件應(yīng)用程序之間的通信方面發(fā)揮著不同的作用。了解應(yīng)用程序接口和端點(diǎn)之間的區(qū)別對于設(shè)計(jì)穩(wěn)健高效的系統(tǒng)至關(guān)重要。
在這篇博文中,我們探討了 API 和端點(diǎn)的概念,強(qiáng)調(diào)了它們的區(qū)別,并提供了詳細(xì)的代碼示例來說明它們的用法。我們還討論了版本控制和速率限制等高級主題,以及設(shè)計(jì) API 的最佳實(shí)踐。
通過遵循這些指導(dǎo)原則和最佳實(shí)踐,您可以創(chuàng)建不僅功能齊全,而且安全、可擴(kuò)展和易于使用的應(yīng)用程序接口。 無論您是在構(gòu)建簡單的應(yīng)用程序還是復(fù)雜的系統(tǒng),對應(yīng)用程序接口和端點(diǎn)的扎實(shí)了解都將有助于您提供高質(zhì)量的軟件解決方案。
原文鏈接:https://medium.com/@nile.bits/apis-vs-endpoints-breaking-down-the-differences-ef80ef128844