
Python實現動圖生成:輕松創建自定義表情包
在本示例中,API 定義了多個用于管理圖書的端點(路由)。每個端點都允許客戶對圖書資源執行特定操作。
端點是提供特定服務的特定 URL 模式。它代表通信通道的一端,通常與應用程序接口公開的操作相對應。
端點是應用程序接口的重要組成部分。它們定義了訪問或操作資源的位置和方式。
繼續前面的例子,讓我們來確定端點:
GET /books:獲取所有書籍的列表。
POST /books:添加新書
PUT /books/<int:id>: 用指定的 ID 更新圖書。
DELETE /books/<int:id>: 刪除指定 ID 的圖書。
每個端點都執行不同的操作,允許客戶以特定方式與圖書資源交互。
為了進一步說明應用程序接口和端點之間的區別和互動,讓我們擴展前面的示例。我們將添加更多的功能,并展示端點如何在更廣泛的 API 環境中工作。
讓我們為應用程序接口添加身份驗證。只有通過身份驗證的用戶才能添加、更新或刪除圖書。
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)
在本例中,驗證函數會檢查請求是否包含有效的驗證憑證。POST、PUT 和 DELETE 端點受保護,需要有效憑證才能訪問。
讓我們通過添加更詳細的錯誤處理來改進我們的應用程序接口。這樣可以確保客戶在出錯時收到有意義的錯誤信息。
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)
在這個改進版本中,我們為不同的 HTTP 狀態代碼添加了自定義錯誤處理程序。中止函數用于在必要時觸發這些錯誤處理程序,為客戶端提供更多的錯誤信息。
隨著應用程序接口的復雜性不斷增加,管理不同版本和限制請求率以確保穩定性和向后兼容性變得至關重要。
應用程序接口版本管理允許您維護不同版本的應用程序接口,以支持傳統客戶端,同時為新客戶端添加新功能。讓我們為應用程序接口添加版本控制。
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)
在本例中,我們創建了兩個版本的應用程序接口(v1 和 v2)。每個版本都有自己的端點集,允許客戶選擇與哪個版本進行交互。 這種方法有助于保持向后兼容性,同時又能引入新的功能和改進。
速率限制為客戶在一定時間內向應用程序接口發出的請求數量設置了上限。這樣可以確保客戶端之間的公平使用,防止濫用。讓我們使用 flask-limiter 擴展為我們的應用程序接口提供速率限制。
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 擴展用于對不同端點應用速率限制。default_limits 參數設置了全局速率限制,而 @limiter.limit 裝飾器則為單個端點應用了特定的速率限制。 如果客戶端超過了允許的請求數,就會收到 429 請求過多的錯誤信息。
應用程序接口(API)和端點是網絡開發中的基本概念,各自在實現軟件應用程序之間的通信方面發揮著不同的作用。了解應用程序接口和端點之間的區別對于設計穩健高效的系統至關重要。
在這篇博文中,我們探討了 API 和端點的概念,強調了它們的區別,并提供了詳細的代碼示例來說明它們的用法。我們還討論了版本控制和速率限制等高級主題,以及設計 API 的最佳實踐。
通過遵循這些指導原則和最佳實踐,您可以創建不僅功能齊全,而且安全、可擴展和易于使用的應用程序接口。 無論您是在構建簡單的應用程序還是復雜的系統,對應用程序接口和端點的扎實了解都將有助于您提供高質量的軟件解決方案。
原文鏈接:https://medium.com/@nile.bits/apis-vs-endpoints-breaking-down-the-differences-ef80ef128844