ebSkola

12.2 Flask: Python kā web serveris

Stundas uzdevums: Uzbūvēt savu pirmo Flask web serveri ar vairākām maršrutēm un atgriezt JSON datus.

SR 2.4.11. Lieto standartizētas bibliotēkas un API SR 2.4.15. Modulāras programmas un funkcijas SR 2.4.2. Programmēšanas rīku un bibliotēku izvēle

70 min plāns: Teorija un paraugs (~10 min) · 1. uzdevums (~15 min) - palaid pirmo Flask serveri · 2. uzdevums (~25 min) - atgriez JSON no maršruta · 3. uzdevums (~20 min) - pieņem datus ar POST. Papildu uzdevumu sāc tikai tad, ja pārējie trīs ir gatavi.

Pirms sāc: aktivizē virtuālo vidi un izpildi pip install flask. Serveri apturēsi ar Ctrl+C terminālī.

Teorija: Flask pamatkomponenti

Flask ir mikro-ietvars Python - tikai 100 KB, bet pietiekams reāliem projektiem. Instalācija: pip install flask.

from flask import Flask, jsonify, request

app = Flask(__name__)

# Vienkārša maršruta
@app.route("/")
def home():
    return "<h1>Sveiks!</h1>"

# JSON atbilde
@app.route("/api/speletaji")
def saraksts():
    return jsonify([
        {"vards": "Anna", "punkti": 120},
        {"vards": "Jānis", "punkti": 95}
    ])

# Maršruta ar parametru
@app.route("/api/speletajs/<int:id>")
def viens(id):
    return jsonify({"id": id, "vards": "Anna"})

# POST pieprasījums
@app.route("/api/saglabat", methods=["POST"])
def saglabat():
    dati = request.json
    return jsonify({"status": "ok", "saņēmu": dati}), 201

if __name__ == "__main__":
    app.run(debug=True, port=5000)

Palaiž ar python app.py → atver http://localhost:5000/.

Praktiskie uzdevumi

1. uzdevums -

Palaid pirmo Flask serveri

Beigās tavs Python kods atbildēs pārlūkam.

  1. Izveido failu serveris.py un ieraksti from flask import Flask.
  2. Ieraksti app = Flask(__name__).
  3. Pievieno dekoratoru @app.route("/").
  4. Uzraksti zem tā funkciju, kas atgriež "<h1>Sveiks!</h1>".
  5. Pievieno faila beigās app.run(debug=True).
  6. Palaid un atver pārlūkā http://localhost:5000.

Gatavs, kad: pārlūkā redzams liels uzraksts Sveiks!, un terminālī parādās ieraksts par pieprasījumu.

2. uzdevums -

Atgriez JSON no maršruta

Beigās serveris atdos datus, nevis tekstu.

  1. Importē jsonify no Flask.
  2. Pievieno maršrutu @app.route("/api/speletaji").
  3. Atgriez tajā jsonify([{"vards": "Anna", "punkti": 120}]).
  4. Atver pārlūkā /api/speletaji un apskati rezultātu.
  5. Atgriez to pašu bez jsonify un pieraksti, kas notiek.
  6. Ieliec jsonify atpakaļ.
  7. Pārbaudi F12 Network cilnē, kāds ir atbildes Content-Type.

Gatavs, kad: atbildes Content-Type ir application/json, nevis text/html.

3. uzdevums -

Pieņem datus ar POST

Beigās serveris varēs saņemt jaunu ierakstu.

  1. Izveido sarakstu SPELETAJI = [] faila augšā.
  2. Pievieno maršrutu ar methods=["POST"].
  3. Nolasi tajā dati = request.json.
  4. Pievieno datus sarakstam un atgriez tos ar statusa kodu 201.
  5. Izmēģini to ar curl -X POST -H "Content-Type: application/json" -d '{"vards":"Jānis"}' http://localhost:5000/api/speletaji.
  6. Atver GET maršrutu un pārbaudi, ka jaunais ieraksts tur ir.
  7. Pieraksti vienu secinājumu: kāpēc dati pazūd, kad serveri restartē.

Gatavs, kad: pēc POST pieprasījuma GET maršruts rāda jauno spēlētāju, bet pēc servera restarta saraksts atkal ir tukšs.

Papildu uzdevums - Pievieno maršrutu ar parametru

Ja pamatdarbs ir gatavs, ļauj pieprasīt vienu konkrētu spēlētāju.

  1. Pievieno maršrutu @app.route("/api/speletaji/<int:id>").
  2. Atrodi sarakstā spēlētāju ar šo id.
  3. Atgriez to kā JSON.
  4. Atgriez statusa kodu 404, ja spēlētājs nav atrasts.
  5. Pārbaudi abus gadījumus pārlūkā.

Gatavs, kad: esošs id atgriež spēlētāju, bet neesošs - kodu 404, nevis servera kļūdu.

Biežākās kļūdas

  • Aizmirsts jsonify(): Bez tā Flask atgriež dictionary kā string, ne JSON.
  • Ports aizņemts: OSError: Address already in use - nogalini iepriekšējo procesu vai mainī portu.
  • JSON parametra trūkums: request.json ir None, ja klients nesūta Content-Type: application/json.

Koda piemērs

from flask import Flask, jsonify, request

app = Flask(__name__)
SPELETAJI = [{"id": 1, "vards": "Anna", "punkti": 120}]

@app.route("/api/speletaji")
def visi():
    return jsonify(SPELETAJI)

@app.route("/api/speletaji", methods=["POST"])
def pievienot():
    d = request.json
    if not d or "vards" not in d:
        return jsonify({"kluda": "Trūkst vārds"}), 400
    jauns = {"id": len(SPELETAJI) + 1, "vards": d["vards"], "punkti": d.get("punkti", 0)}
    SPELETAJI.append(jauns)
    return jsonify(jauns), 201

if __name__ == "__main__":
    app.run(debug=True)
GET /api/speletaji → [{...}]
POST /api/speletaji → 201 Created