文章

Flask - 處理請求與響應

目標

  • 使用 request 對象處理不同類型的請求數據
  • 返回 JSON 格式的響應
  • 設置合適的 HTTP 狀態碼

步驟

  1. 準備環境
    • 確保虛擬環境已激活,並使用前兩天的 app.py 作為基礎。如果需要,可以從頭開始:
      1
      2
      3
      
      # 激活虛擬環境
      # Windows: flask_api_env\Scripts\activate
      # macOS/Linux: source flask_api_env/bin/activate
      
  2. 處理不同類型的請求數據
    • 我們將擴展昨天的 “items” API,添加查詢參數和 JSON 數據處理。修改 app.py 如下:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      
      from flask import Flask, jsonify, request
      
      app = Flask(__name__)
      
      # 模擬數據庫
      items = [
          {'id': 1, 'name': 'Item 1', 'price': 10.0},
          {'id': 2, 'name': 'Item 2', 'price': 20.0}
      ]
      
      # GET - 獲取所有項目,支持查詢參數過濾
      @app.route('/items', methods=['GET'])
      def get_items():
          # 獲取查詢參數 'max_price'
          max_price = request.args.get('max_price', type=float)
          if max_price:
              filtered_items = [item for item in items if item['price'] <= max_price]
              return jsonify({'items': filtered_items})
          return jsonify({'items': items})
      
      # POST - 創建新項目,處理 JSON 數據
      @app.route('/items', methods=['POST'])
      def create_item():
          if not request.is_json:
              return jsonify({'error': 'Request must be JSON'}), 400
          data = request.get_json()
          if 'name' not in data or 'price' not in data:
              return jsonify({'error': 'Missing name or price'}), 400
          new_item = {
              'id': len(items) + 1,
              'name': data['name'],
              'price': data['price']
          }
          items.append(new_item)
          return jsonify(new_item), 201
      
      # PUT - 更新項目,支持部分更新
      @app.route('/items/<int:item_id>', methods=['PUT'])
      def update_item(item_id):
          item = next((item for item in items if item['id'] == item_id), None)
          if not item:
              return jsonify({'error': 'Item not found'}), 404
          if not request.is_json:
              return jsonify({'error': 'Request must be JSON'}), 400
          data = request.get_json()
          item.update({k: v for k, v in data.items() if k in ['name', 'price']})
          return jsonify(item), 200
      
      if __name__ == '__main__':
          app.run(debug=True)
      
    • 代碼解釋
      • request.args.get('max_price', type=float):從查詢參數中獲取 max_price,並轉換為浮點數。
      • request.is_json:檢查請求是否為 JSON 格式。
      • request.get_json():解析 JSON 數據。
      • 狀態碼:400 表示客戶端錯誤,201 表示創建成功,200 表示成功。
  3. 運行應用
    • 保存並運行:
      1
      
      python app.py
      
  4. 測試 API 端點
    • 使用 Postman 或瀏覽器測試以下場景:
      • GET /items?max_price=15
        • 方法:GET
        • URL:http://127.0.0.1:5000/items?max_price=15
        • 預期響應:{"items": [{"id": 1, "name": "Item 1", "price": 10.0}]}
      • POST /items
        • 方法:POST
        • URL:http://127.0.0.1:5000/items
        • Body (JSON):{"name": "Item 3", "price": 30.0}
        • 預期響應:{"id": 3, "name": "Item 3", "price": 30.0}
        • Headers:Content-Type: application/json
      • PUT /items/1
        • 方法:PUT
        • URL:http://127.0.0.1:5000/items/1
        • Body (JSON):{"price": 15.0}
        • 預期響應:{"id": 1, "name": "Item 1", "price": 15.0}
      • 錯誤測試
        • POST 無 JSON:應返回 400 和錯誤訊息。
        • PUT 無效 ID:應返回 404
  5. 進階:處理表單數據
    • 添加一個新路由來處理表單提交(模擬傳統表單場景):
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      @app.route('/items/form', methods=['POST'])
      def create_item_from_form():
          name = request.form.get('name')
          price = request.form.get('price', type=float)
          if not name or not price:
              return jsonify({'error': 'Missing name or price'}), 400
          new_item = {'id': len(items) + 1, 'name': name, 'price': price}
          items.append(new_item)
          return jsonify(new_item), 201
      
    • 在 Postman 中測試:
      • 方法:POST
      • URL:http://127.0.0.1:5000/items/form
      • Body:選擇 x-www-form-urlencoded,輸入 name=Item 4price=25.0
      • 預期響應:{"id": 4, "name": "Item 4", "price": 25.0}
  6. 作業
    • 修改 GET /items 端點,支持根據名稱模糊查詢(提示:檢查 name 是否包含查詢參數 name)。
    • 添加一個新端點,返回所有項目的平均價格。

注意事項

  • 確保在 Postman 中設置正確的 Content-Type(例如 application/json)。
  • request.args 用於查詢參數,request.form 用於表單數據,request.get_json() 用於 JSON。

本文章以 CC BY 4.0 授權