Kontakt os

Spørg fem udviklere, hvad Flask er, og du får fem selvsikre svar, hvoraf de fleste kun er halvt rigtige. Her er sagens kerne: Et Flask Python-projekt kan gå fra en tom mappe til et fungerende API på en eftermiddag, for derefter – uden bevidste valg omkring struktur, validering og deployment – stille og roligt at blive til det system, som ingen har lyst til at røre ved. Hurtigt at starte. Dyrt at forsømme.
Denne guide dækker begge sider af historien. Hvis du er udvikler, bygger vi et fungerende REST API sammen, trin for trin: CRUD-endpoints, en SQLite-database via SQLAlchemy, request-validering og fejlhåndtering, OpenAPI-dokumentation samt en projektstruktur, der kan holde til vækst.
Hvis du er CTO eller engineering lead og overvejer Python Flask kontra FastAPI, så spring direkte til afsnittene om produktionsparathed og hvordan tekniske ledere bør træffe beslutninger. De afsnit taler dit sprog: teamets ekspertise, leveringsrisiko og hvad vedligeholdelse reelt koster.
Flask er et letvægts-webframework til Python, der bygger API'er og webapplikationer ved at mappe HTTP-ruter til funktioner, som returnerer JSON eller HTML. Det er et WSGI-framework, og WSGI (Web Server Gateway Interface) er ganske enkelt standardforbindelsen mellem Python-webapplikationer og de webservere, der kører dem. Den officielle Flask-dokumentation kalder det et mikroframework, hvilket er både præcist og en smule misvisende på samme tid.
Mikro beskriver kernen, ikke ambitionen. Flask giver dig et chassis frem for en færdig bil: motoren, sæderne og instrumentbrættet er dine valg, plukket fra et reservedelskatalog, som communityet har opbygget siden 2010. Den frihed er hele tiltrækningskraften (og, som vi skal se, hele risikoen).
Python tilbyder adskillige frameworks: blandt andre Tornado, Pyramid, Django og FastAPI. Hvis du stadig overvejer selve sproget, forklarer vores oversigt over fordelene ved Python hvorfor det dominerer backend- og dataarbejde.
Er Flask stadig et mainstream-valg? I høj grad. I 2025 Stack Overflow Developer Surveyrapporterede omkring 15 % af respondenterne, at de bruger Flask, hvilket placerer det sammen med FastAPI blandt de mest anvendte webframeworks på tværs af alle sprog. Reservedelskataloget er lige så modent: Flask-SQLAlchemy til databaser, Flask-Login og Flask-JWT-Extended til autentificering, Flask-Migrate til skemamigreringer, Flask-Limiter til rate limiting. Hver især vedligeholdt gennem årevis.
Fra IC's audit-praksis: Flasks frihed er et tveægget sværd. Det gør de første uger af et Flask Python-projekt hurtige, og det er også den hyppigste årsag til, at vi bliver bedt om at rede trådene ud i en kodebase et år senere. Frameworket forhindrer ikke tre udviklere i at opfinde tre forskellige strukturer i den samme applikation. Det gør intet, undtagen teamet selv.
API står for Application Programming Interface: måden, hvorpå ét system kommunikerer med et andet. En REST-API (Representational State Transfer) er en arkitektonisk stil for denne kommunikation, bygget på tilstandsløse forespørgsler via standard HTTP-metoder, hvor klient- og serveransvar holdes skarpt adskilt.
I praksis udveksler en REST-API JSON og mapper slutpunkter til fire verber: Create (POST), Read (GET), Update (PUT eller PATCH) og Delete (DELETE). Samlet set kaldes de CRUD-operationer, og den API, du bygger i denne guide, implementerer alle fire for en enkelt entitet. REST er dog ikke den eneste stil. Hvis dine tjenester er interne og følsomme over for latenstid, kan vores gRPC vs REST-sammenligning forklare, hvornår en binær protokol er det rette valg.
Fra IC's audit-praksis: det hyppigste problem, vi finder i REST-design, er ikke et manglende slutpunkt. Det er manglende konsistens: én rute returnerer snake_case, en anden camelCase; én pakker fejl ind i JSON, en anden serverer en rå HTML-side. At blive enige om disse konventioner, før det første slutpunkt oprettes, tager en time og sparer uger.
Ethvert Flask API kræver det samme fundament, før den første linje applikationskode skrives. Lad os få det på plads.
Du skal have Python installeret. Koden her forudsætter Python 3; hvis du bruger Windows eller har brug for Python 2, så følg Flask-installationsguiden.
Start med at oprette en mappe til projektet. Kør følgende kommandoer i din terminal på det sted, hvor projektet skal ligge:
mkdir flask_api
cd flask_api
Vi har nu oprettet projektmappen og navigeret ind i den. Før du installerer noget, skal du oprette et virtuelt miljø:
python3 -m venv venv
Dette opretter en mappe ved navn venv i dit projekt. Aktivér det ved at køre:
source venv/bin/activate
# On Windows:
venv\Scripts\activate
Fra nu af vil al Python, du kører, bruge venv-miljøet. Hvis du arbejder i et IDE, skal du pege det mod det samme miljø (en klassisk kilde til forvirring, når tingene virker i terminalen, men ikke i editoren).
Hvordan ved du, at det er aktivt? Tjek venstre side af konsollen: Hvis miljøets navn står i parentes, er du klar. For at deaktivere det senere, skal du køre:
deactivate
Et typisk Python Flask API bygges i seks trin:
Denne guide følger denne rækkefølge, fordi vi gør det samme i vores kundeprojekter. Det holder backend-tjenester organiserede fra første commit, fremfor først ved den femtende refaktorering.
.webp)
Et API, der gemmer data i en Python-liste, glemmer alt, så snart serveren genstarter. Rigtige applikationer gemmer data permanent, så i dette afsnit forbinder vi Flask-API'et til en database ved hjælp af SQLite og SQLAlchemy.
SQLite er en letvægtsdatabase, der ikke kræver en separat server, hvilket gør den ideel til selvstudier og mindre applikationer. Perfekt til i dag. Ikke nødvendigvis til lanceringsdagen.
Fra IC's audit-praksis: næsten alle de Flask-projekter, vi overtager, startede med SQLite "bare lige for nu". Det er et fint udgangspunkt, forudsat at SQLAlchemy-modellerne er skrevet, som om PostgreSQL er på vej. For i produktion er det oftest tilfældet.
Installer de nødvendige afhængigheder:
pip install Flask Flask-SQLAlchemy
Hvis du administrerer afhængigheder med en requirements.txt -fil, skal du tilføje:
Flask
Flask-SQLAlchemy
I dette setup er SQLAlchemy din Object Relational Mapper. En ORM (Object Relational Mapper) lader dig håndtere databaseposter som almindelige Python-objekter i stedet for at skrive rå SQL; SQLAlchemy-dokumentationen dækker hele sortimentet. Flask-SQLAlchemy forbinder det med Flask.
Peg Flask mod SQLite-databasen ved at definere forbindelsesstrengen:
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///items.db"
db = SQLAlchemy(app)
Dette opretter en lokal SQLite-databasefil med navnet items.db i projektmappen.
Opret en model, der repræsenterer strukturen af databasetabellen:
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False)
price = db.Column(db.Float, nullable=False)
def to_dict(self):
return {"id": self.id, "name": self.name, "price": self.price}
Modellen Item definerer tre felter: id (unik identifikator), name og pris. to_dict() -metoden konverterer databaseobjektet til en JSON-serialiserbar ordbog.
Før du kører API'et, skal du oprette tabellerne ved hjælp af SQLAlchemy:
with app.app_context():
db.create_all()
Dette endpoint returnerer hvert element, der er gemt i databasen:
@app.route("/items", methods=["GET"])
def get_items():
items = Item.query.all()
return jsonify([item.to_dict() for item in items])
Dette endpoint læser JSON-anmodningens brødtekst, validerer inputtet, opretter en databasepost og returnerer det oprettede element:
@app.route("/items", methods=["POST"])
def create_item():
data = request.get_json()
if not data or "name" not in data or "price" not in data:
return jsonify({"error": "Both 'name' and 'price' are required."}), 400
item = Item(name=data["name"], price=data["price"])
db.session.add(item)
db.session.commit()
return jsonify(item.to_dict()), 201
Dette endpoint henter et specifikt element via dets ID:
@app.route("/items/<int:item_id>", methods=["GET"])
def get_item(item_id):
item = Item.query.get_or_404(item_id)
return jsonify(item.to_dict())Hvis elementet ikke findes, returnerer Flask automatisk en 404-fejl. Ingen ekstra kode påkrævet.
Dette endpoint opdaterer et eksisterende element. Kun de angivne felter bliver ændret.
@app.route("/items/<int:item_id>", methods=["PUT"])
def update_item(item_id):
item = Item.query.get_or_404(item_id)
data = request.get_json() or {}
if "name" in data:
item.name = data["name"]
if "price" in data:
item.price = data["price"]
db.session.commit()
return jsonify(item.to_dict())
Dette endpoint fjerner det angivne element fra databasen:
@app.route("/items/<int:item_id>", methods=["DELETE"])
def delete_item(item_id):
item = Item.query.get_or_404(item_id)
db.session.delete(item)
db.session.commit()
return jsonify({"message": f"Item {item_id} deleted."})
Start Flask-udviklingsserveren:
python app.py
# or, with the Flask CLI:
flask --app app run --debugDin API er nu tilgængelig lokalt.
Opret et nyt element, forespørgslen:
curl -X POST http://localhost:5000/items \
-H "Content-Type: application/json" \
-d '{"name": "Keyboard", "price": 49.9}'
Svaret:
{
"id": 1,
"name": "Keyboard",
"price": 49.9
}
Hent alle elementer, svaret:
[
{
"id": 1,
"name": "Keyboard",
"price": 49.9
}
]
Fordi lister mister data ved genstart, kan ikke deles mellem applikationsinstanser og kan ikke forespørges effektivt. En database som SQLite giver din API persistent, søgbar lagring: den funktionalitet, som en rigtig backend-tjeneste kræver.
Til produktionssystemer skifter teams typisk til PostgreSQL, MySQL eller MongoDB. Den overordnede struktur for Flask-API'et forbliver den samme.
Betragt et API med én fil som en etværelses lejlighed. Alt er inden for rækkevidde, intet kræver en plantegning, og for et lille projekt er det præcis pointen:
flask_api/
├── app.py
├── models.py
├── routes.py
├── requirements.txt
└── items.dbI denne struktur app.py opretter Flask-applikationen og konfigurerer udvidelser, models.py definerer SQLAlchemy-modellerne, routes.py indeholder slutpunkterne, requirements.txt oplister afhængigheder, og items.db er udviklingsdatabasen.
Dette layout passer til små API'er, prototyper og læringsprojekter. Men ingen stifter familie i en etværelses lejlighed, og ingen bør lade et produkt vokse i én enkelt fil.
app.py opretter Flask-applikationen, konfigurerer databasen og registrerer ruterne.
from flask import Flask
from models import db
import routes
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///items.db"
db.init_app(app)
app.register_blueprint(routes.bp)
with app.app_context():
db.create_all()
if __name__ == "__main__":
app.run(debug=True)models.py definerer databasemodellen.
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False)
price = db.Column(db.Float, nullable=False)
def to_dict(self):
return {"id": self.id, "name": self.name, "price": self.price}routes.py indeholder API-slutpunkterne.
from flask import Blueprint, request, jsonify
from models import db, Item
bp = Blueprint("items", __name__)
@bp.route("/items", methods=["GET"])
def get_items():
return jsonify([item.to_dict() for item in Item.query.all()])
# ... remaining CRUD endpoints as in snippets 11-14, using @bp.routeVed at opdele applikationen i filer holdes ansvarsområderne adskilt, og rod minimeres. Hvis du senere tilføjer godkendelse, brugere eller ordrer, udvider du blot strukturen i stedet for at skulle skrive hele projektet om.
Større Python Flask-applikationer kræver et hus frem for en lejlighed: pakker i stedet for filer på øverste niveau, med et dedikeret rum til hvert ansvarsområde.
flask_api/
├── app/
│ ├── __init__.py
│ ├── models/
│ │ └── item.py
│ ├── routes/
│ │ └── items.py
│ └── schemas/
│ └── item.py
├── requirements.txt
└── run.pyI denne arkitektur indeholder app-pakken den primære applikationslogik, models/ definerer databasemodeller, routes/ grupperer slutpunkter efter ressource, og run.py starter applikationen. schemas/ -mappen håndterer validering af forespørgsler og svar ved hjælp af Marshmallow, et Python-bibliotek til definition af skemaer, der validerer indgående data og serialiserer udgående svar.
Gevinsten er enkel. Slutpunkter forbliver organiseret efter ressource, funktioner som godkendelse eller baggrundsopgaver kan nemt tilføjes, og flere udviklere kan arbejde parallelt uden at komme i vejen for hinanden.
Best practice: start med den enkle struktur og udvid kun, når applikationen vokser. Til små projekter er et par tydeligt navngivne filer rigeligt. Til større Flask-API'er er det pakke-baserede layout det, der holder vedligeholdelsesomkostningerne nede.
Et blueprint er et objekt, der minder meget om et Flask-applikationsobjekt, bortset fra at det udvider den eksisterende applikation i stedet for at oprette en ny. Blueprints er måden, du opdeler et Flask-API i sektioner på: efter ressource, API-version eller tjeneste.
Så hvornår har du egentlig brug for dem? Tidligere end du tror.
Fra IC's revisionspraksis: en enkelt fil med ruter begynder at akkumulere merge-konflikter, så snart en anden udvikler kommer til, eller en ny ressource opstår. Det er signalet til at skifte til Blueprints. Ikke først når filen "føles" for lang.
Lad os konvertere koden ovenfor til et blueprint og indlæse det i hovedapplikationen. Opret en ny mappe med navnet blueprints, og indeni den en mappe og en fil til items-blueprintet:
from flask import Blueprint, request, jsonify
from models import db, Item
items_bp = Blueprint("items", __name__, url_prefix="/items")
@items_bp.route("", methods=["GET"])
def get_items():
return jsonify([item.to_dict() for item in Item.query.all()])
# ... remaining CRUD endpoints moved here unchanged
Nu skal app.py blot indlæse det oprettede blueprint og registrere det på applikationsobjektet:
from blueprints.items.routes import items_bp
app.register_blueprint(items_bp)Samme endpoints, bedre struktur. Det er dette, der gør en voksende Flask Python-applikation overskuelig.
Validering er din API's dørmand. Den tjekker legitimationsoplysninger ved indgangen, så du ikke skal trække dårlige data ud af databasen senere, når de allerede har blandet sig med dine rapporter. Et veldesignet Flask-API validerer indgående data, returnerer klare fejlmeddelelser og bruger de korrekte HTTP-statuskoder.
Fra IC's revisionspraksis: i de produktionshændelser, vi bliver tilkaldt for at diagnosticere, er manglende validering af forespørgsler en af de hyppigste årsager. Dårlige data sniger sig ind og dukker først op uger senere som en rapporteringsfejl, der er dyr at spore tilbage til kilden.
Når en klient sender data, bør serveren verificere, at de påkrævede felter er til stede og korrekt formateret. Oprettelse af et nyt element bør for eksempel kræve både et navn og en pris.
Her er et simpelt valideringseksempel:
@app.route("/items", methods=["POST"])
def create_item():
data = request.get_json()
if not data or "name" not in data or "price" not in data:
return jsonify({"error": "Both 'name' and 'price' are required."}), 400
item = Item(name=data["name"], price=data["price"])
db.session.add(item)
db.session.commit()
return jsonify(item.to_dict()), 201API'et tjekker, at anmodningens brødtekst indeholder JSON, og at de påkrævede felter er til stede. Hvis valideringen fejler, returneres et 400 Bad Request -svar. Dørmanden afviser ved døren, høfligt og i JSON.
Statuskoder fortæller klienter, om en anmodning lykkedes eller fejlede. De mest almindelige i REST-API'er er:
Den rigtige kode lader API-brugere håndtere svar programmatisk i stedet for at skulle analysere fejltekst.
Når en klient anmoder om en ressource, der ikke findes, bør API'et returnere en 404-fejl. Flask-SQLAlchemy tilbyder en praktisk hjælper:
@app.route("/items/<int:item_id>", methods=["GET"])
def get_item(item_id):
item = Item.query.get_or_404(item_id)
return jsonify(item.to_dict())
Hvis elementet ikke findes, returnerer Flask automatisk et svar som:
{
"error": "Resource not found"
}Ingen tomme svar, ingen vildledende svar.
I større applikationer bør du definere globale fejlhåndteringer, der returnerer ensartede svar ved almindelige fejl:
@app.errorhandler(400)
def bad_request(error):
return jsonify({"error": "Bad request"}), 400
@app.errorhandler(404)
def not_found(error):
return jsonify({"error": "Resource not found"}), 404
@app.errorhandler(500)
def internal_error(error):
return jsonify({"error": "Internal server error"}), 500Med disse håndteringer returnerer API'et altid struktureret JSON i stedet for standard HTML-fejlsider.
Hvis en klient forsøger at oprette et element uden de påkrævede felter, kan API'et returnere:
{
"error": "Both 'name' and 'price' are required."
}Tydelige fejlmeddelelser gør det muligt for udviklere, der integrerer med dit API, at diagnosticere deres egne fejl uden at skulle læse din kildekode. Dit fremtidige jeg tæller i øvrigt også som en integrerende udvikler.
Sammen holder de ugyldige data ude af databasen, gør svar forudsigelige og lader integratorer fejlfinde hurtigt. Det er standardpraksis i moderne API-udvikling og et ufravigeligt krav i en Flask-tjeneste i produktion.
Moderne API'er bør tilbyde maskinlæsbar dokumentation, så udviklere kan forstå endpoints, forespørgselsformater og svar uden at skulle læse koden. Den dominerende standard er OpenAPI, som beskriver HTTP-API'er i et format, der automatisk kan tolkes af værktøjer.
I Flask er den mest bekvemme vej flask-smorest, et bibliotek der forbinder Flask med OpenAPI 3, validering af forespørgsler og automatisk Swagger UI-dokumentation.
Installer de nødvendige pakker:
pip install flask-smorest marshmallowEller tilføj dem til din requirements.txt -fil:
flask-smorest
marshmallowI dette setup flask-smorest genererer OpenAPI-dokumentationen og styrer API-routing, mens marshmallow (introduceret i afsnittet om struktur) håndterer validering af forespørgsler og serialisering af svar.
Før du opretter endpoints, skal du konfigurere applikationen til at generere dokumentation:
from flask import Flask
from flask_smorest import Api
app = Flask(__name__)
app.config["API_TITLE"] = "Items API"
app.config["API_VERSION"] = "v1"
app.config["OPENAPI_VERSION"] = "3.0.3"
app.config["OPENAPI_URL_PREFIX"] = "/"
app.config["OPENAPI_SWAGGER_UI_PATH"] = "/swagger-ui"
app.config["OPENAPI_SWAGGER_UI_URL"] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist/"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///items_smorest.db"Vigtige indstillinger inkluderer API_TITLE (navnet på dit API), API_VERSION, OPENAPI_VERSION (specifikationsversionen) og OPENAPI_SWAGGER_UI_PATH (hvor den interaktive dokumentation findes, for eksempel /swagger-ui).
Med flask-smorest defineres formen på de data, dit API accepterer og returnerer, ved hjælp af Marshmallow-skemaer. Opret et, der beskriver et element:
from marshmallow import Schema, fields
class ItemSchema(Schema):
id = fields.Int(dump_only=True)
name = fields.Str(required=True)
price = fields.Float(required=True)Ét skema udfører fire opgaver: Det validerer indgående requests, dokumenterer det forventede format, serialiserer responses og genererer præcis OpenAPI-output. Det er derfor, vi anbefaler en skema-først-tilgang.
Opret endpoints ved hjælp af en Blueprint, gruppering af relaterede ruter:
from flask_smorest import Blueprint
blp = Blueprint("items", __name__, url_prefix="/items", description="Operations on items")Hvert blueprint bliver til en sektion i den genererede dokumentation.
Implementer nu endpoints til oprettelse og hentning af elementer:
@blp.route("/")
class ItemList(MethodView):
@blp.response(200, ItemSchema(many=True))
def get(self):
return Item.query.all()
@blp.arguments(ItemSchema)
@blp.response(201, ItemSchema)
def post(self, new_data):
item = Item(**new_data)
db.session.add(item)
db.session.commit()
return itemHer @blp.arguments validerer den indgående anmodnings brødtekst, @blp.response dokumenterer og serialiserer outputtet, og MethodView grupperer flere HTTP-metoder under én rute. Dekoratorerne opdaterer automatisk OpenAPI-dokumentationen.
Registrer blueprintet med API-instansen for at aktivere endpoints:
api.register_blueprint(blp)
Når applikationen kører, skal du åbne Swagger UI-URL'en i din browser:
http://localhost:5000/swagger-uiDet interaktive Swagger UI giver dig mulighed for at se alle endpoints, inspicere parametre, teste anmodninger direkte fra browseren og udforske skemaer. Da OpenAPI er en industristandard, driver den samme specifikation desuden klientgenerering og automatiserede API-testværktøjer.
Kan den indbyggede Flask-server håndtere produktion? Nej. Den er kun til udvikling, og produktionsmiljøer kræver en WSGI-server og en webserver for at kunne håndtere reel trafik pålideligt.
Fra IC's audit-praksis: et tilbagevendende fund i vores gennemgange er Flask-udviklingsservere, der er sat i produktion, fordi det "virker". Det gør det også. Lige indtil der kommer samtidig trafik.
En almindelig deployment-opsætning kombinerer Gunicorn eller uWSGI som WSGI-server med Nginx som reverse proxy, hostet på en cloud- eller containerplatform såsom AWS, Azure eller Google Cloud. Gunicorn og uWSGI er WSGI-servere i produktionskvalitet: programmer, der kører flere kopier af din Python-applikation og håndterer indgående forespørgsler, hvilket er præcis den opgave, den enkelttrådede udviklingsserver aldrig var designet til.
Kør for eksempel en Flask-applikation i produktion ved hjælp af Gunicorn:
gunicorn -w 4 "app:app"I denne kommando -w 4 starter fire worker-processer og app:app refererer til Flask-applikationsobjektet.
I moderne miljøer leveres Flask-API'er normalt som Docker-containere, hvilket forenkler skalering, miljøstyring og løbende udrulning. Hvis dit team bruger Kubernetes, gennemgår vores guide til opbygning af en Kubernetes-optimeret CI/CD-pipeline hvordan containeriserede API'er som denne bevæger sig fra commit til cluster.
De fleste produktions-API'er begrænser adgangen, så kun autoriserede brugere eller tjenester kan tilgå beskyttede slutpunkter. De gængse metoder er API-nøgler til simpel service-til-service-adgang, JWT (JSON Web Tokens) til brugerautentificering og OAuth 2.0 til tredjepartsintegrationer.
JWT-baseret autentificering er det mønster, vi oftest bruger i Flask-API'er. En bruger logger ind med sine legitimationsoplysninger, serveren udsteder et signeret token, og klienten præsenterer dette token ved hver anmodning i Authorization -headeren (headerens navn bevarer sin amerikanske stavemåde, fordi HTTP-standarden definerer det sådan).
Eksempel på header:
Authorization: Bearer <your-jwt-token>
Udvidelser som Flask-JWT-Extended håndterer token-håndtering og rutebeskyttelse, så du ikke selv skal stå for kryptografien. Med autorisation på plads kan kun tilladte klienter tilgå API'et, følsomme data forbliver beskyttede, og brugen kan overvåges pr. klient.
Fra IC's audit-praksis: vi betragter autentificering som en del af den indledende arkitektur, ikke som en sikkerhedsopgave til sidst. At eftermontere det på tværs af dusinvis af eksisterende slutpunkter er konsekvent dyrere end at designe det ind fra den første rute.
Selvstudier stopper normalt ved "API'et virker". Før vi hos Imaginary Cloud godkender et Flask-API til produktion, skal det bestå vores IC-tjekliste til produktionsklare løsninger – den samme gennemgang, som vi anvender i vores Tekniske og UX-audits.
Fem punkter på den tjekliste mangler i de fleste Flask-guides:
Lad os gennemgå dem én efter én.
Flask leveres med en testklient, der kalder dine endpoints uden at køre en server, og den fungerer naturligt sammen med pytest. En minimal test ser således ud:
import pytest
from app import create_app, db
@pytest.fixture
def client():
app = create_app(testing=True)
with app.test_client() as client:
with app.app_context():
db.create_all()
yield client
def test_create_item(client):
response = client.post("/items", json={"name": "Keyboard", "price": 49.9})
assert response.status_code == 201
assert response.get_json()["name"] == "Keyboard"Enhedstests dækker individuelle funktioner; integrationstests som den ovenfor gennemgår hele forespørgselscyklussen, fra routing via validering og database til serialisering. Kør begge dele i CI ved hvert commit mod en midlertidig database.
Database-URL'er, JWT-signeringsnøgler og tredjepartsoplysninger må aldrig være hardcodede eller committet til versionsstyring. Læs dem i stedet fra miljøvariabler. Lokalt gør en .env fil indlæst med python-dotenv det nemt:
import os
from dotenv import load_dotenv
load_dotenv()
SQLALCHEMY_DATABASE_URI = os.environ["DATABASE_URL"]
JWT_SECRET_KEY = os.environ["JWT_SECRET_KEY"]Tilføj .env til .gitignore. I produktion skal du indsætte de samme variabler via din platforms secret manager (AWS Secrets Manager, Azure Key Vault eller Kubernetes-hemmeligheder).
Rate limiting beskytter API'et mod misbrug og mod velmenende klienter, der sidder fast i retry-loops. Flask-Limiter tilføjer det med få linjer:
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(get_remote_address, app=app, default_limits=["100 per minute"])Grænser pr. rute kan derefter strammes for dyre slutpunkter. Login-ruter og søge-slutpunkter er de sædvanlige kandidater.
Når der opstår en hændelse i produktionen, er logs forskellen på en diagnose, der tager fem minutter, og en, der tager fem timer. Konfigurer Pythons standard logging -modul med struktureret output, og brug Flasks request hooks (en letvægtsform for middleware, der kører kode før og efter hver anmodning) til at tagge hver loglinje med et request-ID:
import logging, uuid
from flask import g, request
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s [%(request_id)s] %(message)s")
@app.before_request
def assign_request_id():
g.request_id = request.headers.get("X-Request-ID", uuid.uuid4().hex)Med request-ID'er på plads kan en fejlbehæftet anmodning spores på tværs af hver loglinje, den har genereret, og på tværs af tjenester, hvis downstream-kald videresender headeren. For fuld overvågelighed bør du sende logfilerne til en aggregator (CloudWatch, Grafana Loki eller en APM-platform som Sentry eller Datadog) i stedet for at lade dem ligge på serveren.
Hvis en browserbaseret frontend bruger dit API fra et andet domæne, blokerer browseren anmodningerne, indtil API'et sender de korrekte CORS-headere (Cross-Origin Resource Sharing). Flask-CORS håndterer dette:
from flask_cors import CORS
CORS(app, origins=["https://app.example.com"])Angiv præcis de origins, dine frontends bruger. At bruge wildcard for origins med * er en almindelig genvej, og en almindelig fund ved sikkerhedsgennemgange, fordi det tillader enhver hjemmeside på internettet at kalde dit API fra brugernes browsere.
Fra IC's audit-praksis: af disse fem er manglende tests det punkt, der afgør, om en kodebase overhovedet kan overdrages til et nyt team. Et utestet Flask-API er ikke færdigt. Det kører bare.
Flask er et af de mest udbredte Python-webframeworks til udvikling af API'er, men det er ikke den eneste mulighed. FastAPI er vokset hurtigt som et moderne framework, der er designet specifikt til højtydende API'er.
Stack Overflow Developer Survey 2025 sætter tal på denne udvikling: FastAPI og Flask bruges hver især af cirka 15 % af respondenterne, og FastAPIs stigning på fem procentpoint fra år til år var en af de største blandt alle webframeworks. Begge er klar til produktion. De er blot uenige om filosofien.
Et detaljeret kig på de tekniske forskelle, der dækker værktøjer, arkitektur og udvikleroplevelse:
| Funktionskategori | Flask | FastAPI |
|---|---|---|
| Udgivelseshistorik | Veltableret (2010) | Moderne (2018) |
| Asynkrone funktioner | Begrænset support | Nativ ASGI |
| Dataintegritet | Kræver Marshmallow | Indbygget (Pydantic) |
| Selvdokumenterende | Kræver udvidelser | Automatisk OpenAPI |
| Læringskompleksitet | Lav | Moderat (type-hints) |
To begreber i denne tabel fortjener en forklaring. ASGI (Asynchronous Server Gateway Interface) er efterfølgeren til WSGI, som gør det muligt for Python-applikationer at håndtere mange forespørgsler på én gang. Pydantic er et Python-bibliotek, der validerer og parser data ved hjælp af type-hints, og det driver FastAPIs indbyggede validering af forespørgsler.
Kort sagt: Flask giver dig en minimal, synkron kerne og lader dig sammensætte validering og dokumentation ved hjælp af udvidelser som Marshmallow og flask-smorest. FastAPI vender denne tilgang om. Asynkron håndtering, validering og OpenAPI-dokumentation er indbygget, på bekostning af et nyere økosystem og en indlæringskurve for type-hints.
Flask passer godt, når du har brug for et framework, der tilpasser sig applikationen frem for omvendt: små og mellemstore API'er, mikrotjenester, backend-tjenester til webapplikationer og projekter, der kræver fuld kontrol over arkitekturen. Det er også det pragmatiske valg for teams, der allerede er fortrolige med Flask eller dets økosystem af udvidelser.
For at være helt ærlig, så er der projekter, hvor vi ikke ville vælge Flask. Hvis din API er et nyt projekt, async-first og forventes at håndtere tusindvis af samtidige forbindelser (chat, streaming, højfrekvente integrationer), så gør FastAPIs indbyggede ASGI-model det samme ud af boksen, som Flask kræver workarounds for. Det samme gælder, hvis dit team er nyt i begge frameworks, og projektet læner sig op ad omfattende request-validering: Pydantics indbyggede tjek fjerner en arbejdsbyrde, som Flask ellers overlader til din egen disciplin.
FastAPI er bygget specifikt til API'er og leveres med mere funktionalitet ud af boksen, som FastAPI-dokumentationen beskriver i detaljer. Det er det stærkere valg til højtydende og asynkrone API'er, kodebaser der benytter Pythons type hints, og teams der ønsker validering og interaktiv dokumentation genereret automatisk frem for at skulle sammensætte det via udvidelser.
Det er ærligt talt det forkerte spørgsmål. Flask tilbyder maksimal fleksibilitet og seksten års modenhed i økosystemet; FastAPI tilbyder indbygget async samt indbygget validering og dokumentation. De afgørende faktorer er dit teams erfaring, projektets krav og de risikovurderinger, vi gennemgår herunder – de samme faktorer, der driver enhver beslutning om teknologistak.
For CTO'er og tekniske ledere handler spørgsmålet om Flask vs. FastAPI sjældent om benchmarks. Det handler om risiko: ansættelsesrisiko, leveringsrisiko og de langsigtede omkostninger ved at vedligeholde det, dit team leverer i dette kvartal.
Flask er det valg, der indebærer mindst risiko, når dit team allerede kender det. Udviklere med mange års Flask-erfaring leverer hurtigere og begår færre arkitektoniske fejl, end de ville gøre i et framework, der skal læres under tidspres, og Flasks modne økosystem betyder færre ukendte faktorer, når systemet er i drift. Desuden trækker det på en af de største puljer af udviklere inden for Python-webudvikling (omkring hver syvende udvikler i 2025 Stack Overflow-undersøgelsen bruger det allerede), hvilket er vigtigt, når teamet skal vokse.
FastAPI reducerer en anden type risiko. Til async-tunge API'er med høj gennemstrømning fjerner den indbyggede validering og dokumentation hele kategorier af fejl, som Flask-teams er nødt til at forebygge gennem disciplin og udvidelser.
Afvejningen handler om tid til markedet nu kontra vedligeholdelsesomkostninger senere. I de kodebaser, vi auditerer, er de systemer, der er dyrest at vedligeholde, sjældent bygget på det "forkerte" framework: Det er dem, hvor hver udvikler validerede forespørgsler forskelligt, og hvor ingen skrev tests. Disse mangler akkumuleres som teknisk gæld uanset hvilket framework du har valgt.
Hvad koster det over tolv måneder? Mønsteret er konsekvent: Levering af nye funktioner går langsommere, da hver ændring kræver genindlæring af udokumenteret adfærd, onboarding af en ny udvikler strækker sig fra dage til uger, og det tager længere tid end nødvendigt at diagnosticere den første alvorlige hændelse. Det er her, og ikke i valget af framework, at en struktureret arkitekturgennemgang tjener sig selv hjem.
Kort fortalt: Flask er et letvægts Python-webframework, der har været i løbende udvikling siden 2010, og som bygger REST API'er ved at mappe HTTP-ruter til funktioner. Et produktionsklart Flask API tilføjer fem ting til den grundlæggende tutorial-version: database-persistens via SQLAlchemy, anmodningsvalidering med meningsfulde fejlmeddelelser, OpenAPI-dokumentation genereret med flask-smorest, en pakkebaseret projektstruktur ved hjælp af Blueprints samt deployment bag en produktions-WSGI-server som f.eks. Gunicorn.
FastAPI er det primære alternativ, som er hurtigere til asynkrone arbejdsbelastninger og selvdokumenterende fra start. Valget mellem dem bør baseres på teamets ekspertise og vedligeholdelsesomkostninger, ikke på benchmarks.
Hvis du kun skal huske én ting, så lad det være denne: Frameworks skaber ikke vedligeholdelsesomkostninger. Det gør vaner.
En Flask API er en RESTful webtjeneste bygget med Flask-frameworket i Python. Den eksponerer HTTP-endepunkter, som klienter kalder, og udveksler typisk data i JSON-format.
Ja. Flask fungerer som backend for API'er, der forsyner frontend-applikationer, mobilapps eller tredjepartstjenester. Udvidelser håndterer de understøttende funktioner: Flask-SQLAlchemy til data, Flask-JWT-Extended til autentificering og Flask-Limiter til hastighedsbegrænsning.
Flask er et web-framework; REST er en arkitektonisk stil til design af netværksapplikationer. Du bruger Flask til at implementere REST API'er: Frameworket leverer routing og forespørgselshåndtering, mens REST leverer designkonventionerne.
Ja, af en specifik årsag: Dens lille kerne betyder, at API'en kun indeholder det, du selv tilføjer. Bagsiden af medaljen er, at validering, dokumentation og struktur er dit ansvar, og denne guide dækker, hvordan du tilføjer hver af disse dele.
Ja. Omkring 15 % af respondenterne i 2025 Stack Overflow Developer Survey bruger Flask, hvilket er på niveau med FastAPI, og dens økosystem af udvidelser har haft seksten års kontinuerlig vedligeholdelse. Det, der har ændret sig, er standardvalget til nye, asynkront tunge API'er, hvor FastAPI nu er det mest almindelige valg.
Vælg Flask, hvis dit team allerede kender det, hvis API'en ikke er asynkront tung, eller hvis du udvider et eksisterende Flask-system. Vælg FastAPI til nye projekter, systemer med høj gennemstrømning eller asynkront-første API'er, hvor indbygget validering og dokumentation reducerer leveringsrisikoen. Den fulde analyse af fordele og ulemper findes i afsnittet for tekniske ledere ovenfor.
Ved synkrone CRUD-arbejdsbelastninger bag en korrekt konfigureret WSGI-server er det sjældent frameworket, der er flaskehalsen. Det er som regel databasen. FastAPI trækker klart fra ved I/O-bundne, samtidige arbejdsbelastninger, hvor dens native ASGI-model håndterer mange samtidige forespørgsler, som hver især ville optage en Flask-worker.
De løser forskellige problemer. Flask er et mikro-framework, der starter minimalistisk og udvides efter behov; Django leveres med indbygget ORM, administrationsgrænseflade og godkendelse. Vælg Flask til API'er og mikrotjenester, hvor du ønsker kontrol; vælg Django, når du vil have alt inkluderet og kan acceptere dens konventioner.
Ja, med den rette server. Den indbyggede udviklingsserver er ikke sikker til produktion, så ved deployment kører man en WSGI-server som Gunicorn eller uWSGI bag en reverse proxy som Nginx, typisk inde i Docker-containere. Konfigureret på den måde håndterer Flask produktionsbelastninger pålideligt.
Med en WSGI-server og en reverse proxy. De grundlæggende trin er:
En typisk Gunicorn-kommando ser således ud:
gunicorn -w 4 "app:app"I moderne infrastruktur leveres hele denne stack som en Docker-container på AWS, Azure eller Google Cloud.
Installer Flask-CORS-udvidelsen og registrer den i din app med de præcise origins, som dine frontends benytter. Undgå at bruge wildcard for origins med * i produktion, da det gør det muligt for enhver hjemmeside at kalde dit API fra de besøgendes browsere. Sektionen om produktionsklargøring ovenfor viser opsætningen på to linjer.
Forskellen ligger i mængden af indbygget struktur. Flask er et letvægts-mikroframework, hvor du selv vælger biblioteker og arkitektur; Django REST Framework er et fuldt udstyret lag oven på Django, der inkluderer autentificering, serialisering, rettighedsstyring og API-views.
Generelt egner Flask sig bedst til små og mellemstore API'er, mikrotjenester og specialtilpassede arkitekturer, mens Django REST Framework er velegnet til større applikationer, der drager fordel af Djangos integrerede økosystem og konventioner.
Hvis dit team skal beslutte, hvordan et nyt API skal struktureres, eller hvis I er ved at flytte en eksisterende tjeneste til produktion, kan Imaginary Cloud gennemgå jeres arkitektur og finde den rette tilgang til jeres behov og team. Kontakt os for at starte dialogen.
.webp)

Associeret udvikler, der arbejder mest med Backend-teknologier. En iværksætter med datavidenskabsinteresse. Kærlighed til sport, lydbøger, kaffe og memes!

CEO @ Imaginary Cloud og medforfatter af bogen Product Design Process. Jeg nyder mad, vin og Krav Maga (ikke nødvendigvis i denne rækkefølge).

Alexandra Mendes er Senior Growth Specialist hos Imaginary Cloud med 3+ års erfaring med at skrive om softwareudvikling, AI og digital transformation. Efter at have gennemført et frontend-udviklingskursus fik Alexandra nogle praktiske kodningsevner og arbejder nu tæt sammen med tekniske teams. Alexandra brænder for, hvordan nye teknologier former erhvervslivet og samfundet, og hun nyder at omdanne komplekse emner til klart og nyttigt indhold for beslutningstagere.
People who read this post, also found these interesting: