from flask import Flask, jsonify, request
app = Flask(__name__)
books = [
{'id': 1, 'title': '1984', 'author': 'George Orwell'},
{'id': 2, 'title': 'To Kill a Mockingbird', 'author': 'Harper Lee'}
]
@app.route('/books', methods=['GET'])
def get_books():
return jsonify(books)
@app.route('/books', methods=['POST'])
def add_book():
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):
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):
global books
books = [b for b in books if b['id'] != id]
return '', 204
if __name__ == '__main__':
app.run(debug=True)

在本示例中,API 定義了多個用于管理圖書的端點(diǎn)(路由)。每個端點(diǎn)都允許客戶對圖書資源執(zhí)行特定操作。

什么是端點(diǎn)?

端點(diǎn)是提供特定服務(wù)的特定 URL 模式。它代表通信通道的一端,通常與應(yīng)用程序接口公開的操作相對應(yīng)。

端點(diǎn)是應(yīng)用程序接口的重要組成部分。它們定義了訪問或操作資源的位置和方式。

示例:網(wǎng)絡(luò)應(yīng)用程序接口中的端點(diǎn)

繼續(xù)前面的例子,讓我們來確定端點(diǎn):

GET /books:獲取所有書籍的列表。

POST /books:添加新書

PUT /books/<int:id>: 用指定的 ID 更新圖書。

DELETE /books/<int:id>: 刪除指定 ID 的圖書。

每個端點(diǎn)都執(zhí)行不同的操作,允許客戶以特定方式與圖書資源交互。

應(yīng)用程序接口與端點(diǎn)的主要區(qū)別

  1. 范圍:應(yīng)用程序接口:應(yīng)用程序接口(API)是一個更寬泛的概念,包括一套用于構(gòu)建和集成軟件應(yīng)用程序的規(guī)則和定義。它包括多個端點(diǎn)。端點(diǎn):端點(diǎn)是 API 中執(zhí)行特定功能的特定 URL 模式。
  2. 功能:應(yīng)用程序接口:應(yīng)用程序接口(API)定義了不同軟件組件的交互方式。它為訪問應(yīng)用程序的功能和數(shù)據(jù)提供了一個完整的接口。端點(diǎn):端點(diǎn)是應(yīng)用程序接口中執(zhí)行操作的特定交互點(diǎn)。
  3. 結(jié)構(gòu):應(yīng)用程序接口:應(yīng)用程序接口由多個端點(diǎn)組成,每個端點(diǎn)處理應(yīng)用程序功能的特定部分。端點(diǎn):端點(diǎn)是應(yīng)用程序接口中與特定操作相對應(yīng)的一個點(diǎn)。

詳細(xì)代碼示例

為了進(jìn)一步說明應(yīng)用程序接口和端點(diǎn)之間的區(qū)別和互動,讓我們擴(kuò)展前面的示例。我們將添加更多的功能,并展示端點(diǎn)如何在更廣泛的 API 環(huán)境中工作。

添加身份驗(yà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)用程序接口版本化

應(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 請求過多的錯誤信息。

設(shè)計(jì)應(yīng)用程序接口和端點(diǎn)的最佳實(shí)踐

  1. 一致性:確保 API 端點(diǎn)遵循一致的命名規(guī)范和結(jié)構(gòu)。這將使客戶更容易理解和使用您的應(yīng)用程序接口。
  2. 版本控制:使用版本管理來管理 API 的更改和改進(jìn),而不會破壞現(xiàn)有客戶端。為清晰起見,請首選基于 URL 的版本(如 /v1/resource)。
  3. 文檔:為您的應(yīng)用程序接口提供全面的最新文檔。包括有關(guān)可用端點(diǎn)、請求/響應(yīng)格式、驗(yàn)證方法和錯誤處理的信息。
  4. 錯誤處理:實(shí)施有意義的錯誤信息和適當(dāng)?shù)?HTTP 狀態(tài)代碼。這有助于客戶了解出錯的原因以及如何修復(fù)。
  5. 安全性:使用驗(yàn)證和授權(quán)機(jī)制保護(hù)您的應(yīng)用程序接口。確保使用 HTTPS 安全傳輸敏感數(shù)據(jù)。
  6. 速率限制:實(shí)施速率限制,防止濫用并確保公平使用。根據(jù) API 和客戶的需求自定義速率限制。
  7. 測試:徹底測試您的應(yīng)用程序接口,確保其按預(yù)期運(yùn)行。使用自動化測試工具來覆蓋各種場景和邊緣情況。
  8. 監(jiān)控:監(jiān)控您的應(yīng)用程序接口,以便及時發(fā)現(xiàn)并解決問題。使用日志和監(jiān)控工具跟蹤性能、錯誤和使用模式。

結(jié)論

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

推薦閱讀:
REST API:關(guān)鍵概念、最佳實(shí)踐和優(yōu)勢
7個API業(yè)務(wù)模型術(shù)語
了解異步API
API 安全策略和基礎(chǔ)指南
在線API描述規(guī)范、發(fā)現(xiàn)與文檔入門
API設(shè)計(jì)模式:粒度細(xì)化 vs 粒度粗化的利弊分析

上一篇:

首次構(gòu)建 API 時的 10 個錯誤狀態(tài)代碼以及如何修復(fù)它們

下一篇:

常見問題解答:什么是 API Key 密鑰?
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊

多API并行試用

數(shù)據(jù)驅(qū)動選型,提升決策效率

查看全部API→
??

熱門場景實(shí)測,選對API

#AI文本生成大模型API

對比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個渠道
一鍵對比試用API 限時免費(fèi)

#AI深度推理大模型API

對比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費(fèi)