====== Flask Webserver ====== ===== Grundgerüst ===== ==== Übersicht ==== Erstelle folgende Files * Flask-App `app.py` in Hauptordner * HTML-Seite `index.html` in Unterordner `templates` * CSS- & JavaScript-Files `style.css` & `script.js` in Unterordner `static` ==== Setup & Ausführen ==== * Installiere Flask with pip * Führe `app.py` aus, dann klicke auf den Link in der Konsole und du solltest auf die Website gelangen. ==== Files im Detail ==== from flask import Flask, render_template, request, jsonify # import the Flask object from the flask package import datetime import random app = Flask(__name__) # create Flask application instance with name 'app' (name of python file) #app.debug = True # HTTP REQUESTS AND RESPONSES # return root resource index.html for first get request "GET /" @app.route('/') # '/' means that this fcn responds to request for URL /, which is main URL def index(): return render_template('index.html') # can also pass dictionary with data as argument: ...('index.html', data=data_dict) @app.route('/interactWithServer', methods = ['POST']) def do_something(): # is executed whenever client sends request with "let response = await fetch('/interactWithServer', {...." data = request.json['data'] # save data sent by JS in variable # do something with data # e.g. create dictionary with response data data_response = {"name":"Johanna", "age":42} return data_response if __name__ == '__main__': app.run() """ typical shape @app.route(...) # this decorator turns a ... def some_fcn(): # ... regular Python function into a Flask view function which ... ... return ... # ... converts the function's return value into an HTTP response) """ Title ...

My data: {{ data.name_of_key }}

...
Der JavaScript Code hat folgende Struktur. Im nächsten Kapitel werden die wichtigen Elemente im Detail erklärt. // access html elements from withing JS let htmlElement = document.getElementById("idOfMyHtmlElement"); // function that interacts with flask server app async function interactWithServer(word){ // send post request to server let response = await fetch('/interactWithServer', { method: 'POST', // because want to send data to server s.t. it can process it headers: { // tells server that request body contains json data 'Content-Type': 'application/json' }, body: JSON.stringify({"name":"John", "age":41}) // data sent to server }); // write response status (hopefully not 404!) into console console.log(response.status); // wait for server's response, then access data sent back let json_data = await response.json(); // now do something with data htmlElement.innerHTML = json_data.nameOfKey; } // function that is executed on even function somethingHasHappened(event){ // call function that interacts with server interactWithServer(inpPlainText.value); } // add event listeners (clicking button, typing something into input box, ...) htmlElement.addEventListener('input',somethingHasHappened) ===== HTTP-Requests an Server ===== Hier wollen wir anschauen, wie man eine HTTP-Anfrage (Request) an einen Server stellt, um z.B. gewisse Daten zu erhalten. Eine solche Anfrage über das Web dauert ihre Zeit. Damit die ganze Website nicht einfriert bis die Antwort vom Server eingetroffen ist, sollte man seinen Code **asynchron** programmieren. D.h. die Website kann auch anderweitig weiterverwendet werden, während sie noch auf eine Antwort wartet. Dies realisiert man mit `async` und `await`. Einen einfachen HTTP-Request sendet man dann wie folgt: async function sendRequest() { const url = 'https://www.wiewarm.ch/api/v1/bad.json/16'; // state url let fetched = fetch(url); // The fetch(url) function initiates a fetch request to the specified URL. // It returns a PROMISE that resolves to the response to that request. let response = await fetched; // The await keyword pauses the execution of the function until the Promise // returned by fetch(url) is resolved. In this case, it's waiting for the // HTTP request to complete and the response to be available. console.log(response.status) // print response status, e.g. "ok" let json_data = await response.json(); // Once the response is available, await response.json() is used to parse the // response as JSON. Again, we use await to pause until the JSON parsing is complete. console.log(json_data); // do something with data } In `fetch` wird die URL angegeben, von der etwas gefetched werden soll. Dies kann eine fremde Website sein wie `let url = https://www.wiewarm.ch/api/v1/bad.json/16';` oder ein Endpoint für den eigenen Server, z.B. `const url = '/dothis';` Oft möchte man einem HTTP-Request auch Daten anhängen, die dann vom Server verarbeitet werden sollen. Dazu modifiziert man den fetch-Befehl wie folgt: fetch(url, { method: 'POST', // because want to send data to server s.t. it can process it headers: { // tells server that request body contains json data 'Content-Type': 'application/json' }, body: JSON.stringify({data: dataSend}) // data sent to server }) Es gibt auch noch eine alternative Variante für das Senden eines HTTP-Requests, die obige Variante mit asynv & await ist aber zu bevorzugen. ++++Alternativer Syntax für HTTP-Request| const url = '/dothis'; fetch(url, { method: 'POST', // because want to send data to server s.t. it can process it headers: { // tells server that request body contains json data 'Content-Type': 'application/json' }, body: JSON.stringify({data: dataSend}) // data sent to server }) .then(function(response) { // then-method is called on the promise returned by fetch // console.log(response.status) // console.log(response.ok) return response.json(); // Return the Promise from response.json() to the next .then() in order to access the return data }).then(function(response_data) { // deal with returned data }).catch(error => { // deal with errors // console.error('Error:', error); }) ++++ Sendet man einen HTTP-Request an seinen **Flask-Server**, kann man diesen wie folgt bearbeiten: @app.route('/dothis', methods = ['POST']) def do_this(): ... return {"data": return_data} # data returned to website