En Flask App i molnet
I denna övningen använder vi Flask för att skapa ett eget API som svarar med JSON data. I slutet av övningen driftsätter vi appen i Azure’s cloud.
#Förkunskaper
Du har installerat labbmiljön för kursen och läst igenom artikeln Introduktion till molnet.
#Flask
Flask beskrivs som ett “micro-framework”. Vi vill använda Flask för att skapa ett Application Programming Interface (API). Ett API är ett sätt för olika applikationer att kommunicera med varandra. Det API som vi ska skapa ska svara på olika url’er som vi kallar endpoints
. Vi vill att vårt API ska svara med JSON.
När vi anropar en server från en webbläsare till exempel om vi skriver https://dbwebb.se
görs ett GET-anrop. Så när vi skriver ett API definierar vi de olika endpoints för olika url’er där vi vill att vår server/API ska svara med olika data i JSON-formatet.
Låt oss titta på hur det kan se ut. I din katalog som du skapade och använde i kmom01 skapa en ny underkatalog lager_api
. Vi kommer återanvända denna underkatalogen i inlämningsuppgiften senare i kmomet.
Om du vill titta på ett fullständigt exempel finns ett i moln/flask_starter.
#Virtual Environment
För att vi ska kunna installera externa paket som Flask
och requests
behöver vi berätta för Python att vi vill ha en virtual environment där vi kan spara dessa moduler.
Följa instruktionerna för ditt operativsystem i Flask’s guide för Virtual environments. Du behöver inte skapa en ny katalog om du har gjort det ovan. Om du använder WSL terminalen eller Cygwin terminalen kan du använda instruktionerna för macOS/Linux. Vi ser även till att aktivera vår virtual environment.
Som ett sista steg i installationen installerar vi Flask med hjälp av Pythons pakethanterare pip
.
pip install Flask
#Vår första route
Nu ska vi se så att allt fungerar så här långt. Vi börjar därför med att skapa en fil app.py
i den katalog där du har aktiverat din virtual environment. I filen lägger du in följande:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "Hello World!"
Vi startar igång Flask servern med följande kommandon i en terminal.
export FLASK_APP=app flask run
Om du går till http://localhost:5000
i en webbläsare ska du kunna se Hello World! i webbläsaren.
#Olika routes
Jag skapar ytterligare två routes i app.py
så att den filen ser ut på följande sätt. Förutom de nya routes har jag lagt till en modul från Flask escape
så vi kan städa upp i den data användaren skickar in.
from flask import Flask
from markupsafe import escape
app = Flask(__name__)
@app.route("/")
def hello_world():
return "Hello World!"
@app.route("/another")
def another():
return "Another Hello World!"
@app.route("/dynamic/<name>")
def dynamic(name):
return f"Hello {escape(name)}"
Starta om din Flask server i terminalen och vi bör nu kunna gå till /another
och se “Another Hello World!” och till /dynamic/emil
och se “Hello emil”. Den sista routen är lite speciell då vi utnyttjar variabel reglar. Vi anger <name>
och kan då ange vad som helst efter den andra / och vi får då in den som en variabel i routen.
#Svara med json
I Flask är det enkelt att vårt API svarar med ett JSON svar. Om vi returnerar en Dictionary görs den per automatik om till JSON med hjälp av funktionen jsonify()
. Om du vill se mer information om att svara med JSON är dokumentationen en bra start. En route som svarar med JSON kan alltså se ut på följande sätt:
@app.route("/json/<name>")
def json(name):
return {
"data": {
"name": name
}
}
#Hämta data från ett annat API
I detta kmom och projektet ska vi använda ett JSON-API. JSON står för JavaScript Object Notation och är ett data format som används i stor utsträckning när man skickar formaterad data mellan en server och en klient. JSON är dokumenterad på deras webbplats.
Nedan är en beskrivning av API:t vi ska använda i kursen och hur du kan hämta data från API:t. API:t används i en annan kurs för webbprogrammering och ett extra API-endpoint (URL där vi kan hämta data) har skapats för denna kursen.
Endpointet för denna kursen finns på: https://lager.emilfolino.se/v2/products/everything
Endpointet returnerar ett JSON-textsvar innehållande en lista med ungefär 9000+ element. JSON data kan liknas vid Dictionary datastrukturen i Python. Varje element i listan är en produkt som finns på ett lager. Nedan syns de tre första elementen/objekten i listan.
{ "data": [
{
"id": 1,
"article_number": "1214-RNT",
"name": "Skruv M14",
"description": "Skruv M14, värmförsinkad",
"specifiers": "{\"length\" : \"60mm\", \"width\" : \"14mm\"}",
"stock": 12,
"location": "A1B4",
"price": 10
},
{
"id": 2,
"article_number": "1212-RNT",
"name": "Skruv M12",
"description": "Skruv M12, värmförsinkad",
"specifiers": "{\"length\" : \"60mm\", \"width\" : \"12mm\"}",
"stock": 14,
"location": "A1B5",
"price": 10
},
{
"id": 3,
"article_number": "1210-RNT",
"name": "Skruv M10",
"description": "Skruv M10, värmförsinkad",
"specifiers": "{\"length\" : \"60mm\", \"width\" : \"10mm\"}",
"stock": 20,
"location": "A1B6",
"price": 10
}
]}
För att hämta data från API:t med hjälp av Python kan man använda sig av pip-modulen requests (Dokumentation (Länkar till en externa sida.)). Har du inte installerat modulen sen innan kan den installeras med följande kommando i en terminal:
python3 -m pip install requests
Modulen importeras sedan i ett Python script och vi kan använda den inbyggda funktionen GET.
"""
Program that loads a JSON response from a specified URL
Prints first object of the data-list
"""
import requests
URL = 'https://lager.emilfolino.se/v2/products/everything'
# Use requests module to get JSON data
response = requests.get(URL)
# Turns response json object into a Dictionary
products_dict = response.json()
# Prints first object of the data-list
print(products_dict["data"][0])
# Prints name of first object of the data-list
print(products_dict["data"][0]["name"])
#Förbereda för driftsättning
För att Azures moln ska kunna veta vilka externa moduler vi använder oss och som ska installeras i Azure exporterar vi vår virtual environment med följande kommando i terminalen.
pip freeze > requirements.txt
Vi har nu skapat en fil requirements.txt
som innehåller de paket vi använder oss av. När vi driftsätter lite senare i denna övningen vet Azures moln om att den ska installera de paket som finns i requirements.txt
.
#Driftsättning i Azures Moln
I detta steget ska vi testa att skapa resurser för att köra en web- eller apiapp i Azure, genom att skapa en Azure App Service och en App Service Plan.
Börja med att logga in på Azures portal - portal.azure.com. Här loggar du in med ditt studentkonto.
Längst upp till höger ser du ditt konto, klicka på den och välj den prenumeration som finns tillgänglig för dig: DIDA-{akronym}-DV1615-VT22-LP3
#Skapa en webapp resurs
Det finns flera olika vägar att gå för att skapa upp de resurser vi behöver, enklast är att Klicka på + Skapa resurs.
Välj sedan att skapa en WebApp:
För att kunna skapa resurser i din subscription så behöver du först skapa en resursgrupp att ha dom i, så det är det som definieras först.
Följ övriga inställningar nedan, och välj att skapa upp en ny App Service Plan, och välj Ändra storlek.
Du kommer då till Specifikationsväljaren - välj Dev/Test och prisnivån B1.
Klicka på Använd
Klicka på Granska + Skapa
Du får nu upp en summering av dina val och du kan klicka på Skapa.
#Koppla Visual Studio Code till Azure
Vi öppnar upp Visual Studio Code och säkerställer att vi har öppnat den i katalogen med vår Flask app. Klicka på fliken för Azure App Service Extension som vi lade till i det sista steget i uppsättningen av labbmiljön.
Klicka på Sign in to Azure och logga in med ditt studentkonto (xxxx99@student.bth.se).
Du ska nu se texten Select subscription där din prenumeration ska finnas, välj den.
Du har nu genom Visual Studio Code tillgång till de Azuretjänster som du har skapat upp i din prenumeration.
Om man av någon anledning valt fel konto eller vill växla mellan konton så används View -> Command Palette -> Azure: Sign Out och sedan gör man om inloggningsförfarandet.
Vi ska nu driftsätta vårt API. Välj den WebApp som du skapat i portalen och högerklicka. Välj sedan Deploy to Web App…
Välj den folder som appen ligger i lokalt, välj att inte bygga i molnet utan kör det lokalt, och klicka på Deploy.
När Deployment completed visas så kan du klicka på Browse Website och verifiera att det funkar som det ska.
I Azure App Service Extension i Visual Studio Code kan man se hur deployment har gått och vilka filer som överförts.
Det går också att använda Kudu genom att lägga till .scm efter namnet på din tjänst.
Så om tjänsten till exempel heter https://dv1615-oce-webapp-lab.azurewebsites.net/ . Så når du Kudu genom https://dv1615-oce-webapp-lab.scm.azurewebsites.net/ .
Eftersom denna PAAS-tjänsten använder Linux i botten så finns BASH för att gå igenom den del i folderstrukturen som finns tillgängligt för oss.
#Troubleshooting
Ibland vill inte det sig inte med modulen requests
och då kan nedanstående vara lösningen.
För att få det att funka så kan du behöva låta projektet bygga i Azure istället för lokalt. Det gör du genom att gå in i din webapp i portal.azure.com, välja fliken Configuration -> Application settings -> + New application setting:
Name: SCM_DO_BUILD_DURING_DEPLOYMENT
Value: true
Spara sedan ändringen.
Därefter behöver du sannolikt deploya ditt projekt igen. Eftersom bygget nu sker i Azure istället för lokalt så tar det ett tag efter deployment innan bygget är klart och dina ändringar är fullständigt deployade. För mer information se: Configure a Linux Python app for Azure App Service.
#Annat namn än app.py
En annan lurig sak som är värt att känna till. Om du döper din apps uppstarts-.py fil till något annat än app.py så behöver du definiera i konfiguration vilken fil som ska köras.Det görs i webappens application settings.
Name: FLASK_APP
Value: {ditt filnamn}.py
#Avslutningsvis
Vi har i denna övning tittat på hur man använda Flask för att skapa ett API som hämtar data från ett annat API och svarar med JSON. Vi har dessutom tittat på hur vi kan driftsätta API:t i Azures Cloud.
#Revision history
- 2021-12-07: (A, efo) Skapad inför VT2022.