Institute of Computer Science
  1. Courses
  2. 2023/24 spring
  3. Development of web services and distributed systems (LTAT.06.018)
ET
Log in

Development of web services and distributed systems 2023/24 spring

  • Pealeht
  • Loengud
  • Praktikumid
  • Lahenduste Esitamine

Kümnes praktikum - Mikroteenused II - Veebiliidese loomine

Selles praktikumis loome juurde veel ühe mikroteenuse rakenduse kasutaja liidese jaoks (front-end) ja käivitame loodud mikroteenuse põhise rakenduse dockeri konteineritena.

Viited

  1. Docker'i ülevaade - https://docs.docker.com/get-started/overview/
  2. Docker käsurea käskude ülevaade - https://docs.docker.com/engine/reference/commandline/cli/
  3. Dockerfaili spetsifikatsioon - https://docs.docker.com/engine/reference/builder/

Probleemide korral kontrollige:

  1. Võimalikud probleemid ja nende potentsiaalsed lahendused osa praktikumi juhendi lõpus.
  2. Küsige otse #praktikum-10-front Zulip teemas.
    • Ka siis kui soovite lihtsalt viheid.

Ülesanne 10.1: Mikroteenuste modifitseerimine

Selles ülesandes muudame natukene eelmises praktikumis konteineriseeritud mikroteenuseid:

  1. hs9-flask-api-raamatud
  2. hs9-flask-api-raamatute-otsing

Peame konfigureerima Flask lubama sissetulevaid ühendusi, mis tulevat teistelt aadressidelt ja portidelt, et saaks API päringuid välja kutsuda JavaScipt kaudu. Tavaliselt on keelatud Javascript'i välja kutsumine, mis võtab ühendust kolmandate serveritega, et vältida Cross-Origin Resource Sharing (CORS) turvaprobleeme.

  • Muudame eelmise praktikumi Mikroteenuste koodi.
  • Tehke järgmsed muudatused mõlemas programmis:
    1. requirements.txt faili peame lisama veel ühe teegi:
      • flask-cors
      • flask-cors'i kasutame selleks, et lubada API väljakutsumist teistest mikroteenustest hiljem, kui loome ka veebiliidese oma API'le.
    2. Peame sisse viima ka mõned muudatused Flask rakendusets:
      • Lisage import käsk
        • from flask_cors import CORS
      • Lisage flask-cors teegi konfiguratsioon programmi algusesse peale Flask app objekti loomist:
        • app = Flask(__name__)
          cors = CORS(app, resources={r"/raamatud/*": {"origins": "*"}, r"/raamatu_otsing/*": {"origins": "*"}})
          • See lubab APIt välja kutsuda läbi teiste (javaScript) rakenduste, mis muidu keelatakse ära brauserite poolt (Cross Origin Resource Sharing limitatsioonide tõttu). Lisainfot selle kohta leiate siit: https://flask-cors.readthedocs.io/en/latest/
  • Muutke API programme selliselt:
    • Kontrollige, et raamatutest sõne otsingu meetodi raamatutest_sone_otsimine otspunkt lõppeb / märgiga.
    • Peaks olema selliselt:
      • @app.route('/raamatu_otsing/', methods = ['POST'])
        def raamatutest_sone_otsimine():
    • Muidu võib tekkida lahkheli veebiliidese ja API vahel ja saab CORS veateate
    • Tehke sama ka järgmistemeetodite puhul:
      • @app.route('/raamatud/', methods = ['POST'])
        def raamatu_lisamine():
      • @app.route('/raamatud/', methods = ['GET'])
        def raamatu_nimekiri():

Ülesanne 10.2: Kasutajaliidese loomine

Selles ülesandes loome kolmanda mikroteenuse.

Selleks om HTML-põhise kasutajaliides meie veebiteenuse API mikroteenustele, mis kasutab JavaScript'i, et päringuid saata meie kahe API vastu. Samuti seame selle rakenduse üles eraldi Docker konteinerina.

  • Looge uus projekt/kaust hs10-front-end. Saate vabalt valida failiredaktori (näiteks notepad++) või mõne HTML/JS IDE.
  • Loome sinna kaks faili:
    1. front-end.html - Sisaldab meie veebiliidese HTML koodi ja impodib JavaScrip faili
      • Faili sisu võtke siit: https://raw.githubusercontent.com/pjakovits/wsds/main/p09/front-end.html
    2. apiparingud.js - Sisaldab JavaScript koodi, mis suhtleb meie mikroteenustega.
      • Esialgne faili sisu võtke siit: https://raw.githubusercontent.com/pjakovits/wsds/main/p09/apiparingud.js
  • front-end.html Faili me ei muuda. Selles failis on kaks vormi:
    1. Raamatu loomine
    2. Raamatust sõne otsimine
  • Lisaks on seal HTML plokk, mille kaudu saab POST päringute tulemust näidata kasutajale
  • Lisaks on seal HTML plokk raamatute nimekirja näitamiseks
  • Lisaks imporditakse JavaScript fail: <script type="text/javascript" src="apiparingud.js"></script>
  • Lisaks pannakse eraldi scriptis tööle JavaScript meetod listiraamatud(), mis vastutab raamatute nimekirja pärimise eest API'lt, ning mille me implementeerime ise JavaScript failis hiljem.
  • apiparingud.js failis tuleb meil mõned muudatused teha.
    • Praegu sisaldab see ainult abimeetodeid POST, GET ja DELETE meetodite välja kutsumiseks.
    • Lisaks on POST päringu välja kutsumise JavaScript meetod handleFormSubmit loodud kavalalt.
      • Kui see lisada HTML POST vormi kuulama, siis saab selle abil automaatselt saata vormi target aadressile POST päringu, millega pannakse kaasa JSON dokument, mis sisaldab kõiki selle HTML vormi input tüüpi sisendeid.
      • Samuti saab see JavaScript meetod kätte REST POST päringu vastuse JSON dokumendina.
      • Ning seda ilma, et kasutaja brauseri kaudu edasi suunataks API aadressile. Mis võimaldab meil POST päringut taustal läbi viia kui kasutaja vajutab HTM vormi submit nupul
      • Mõlemale HTML vormi (raamatu loomine ning raamatutest otsimine) submit nupule on handleFormSubmit juba HTML failis lisatud

Veebiliidest saab testida avades HTML faili brauseri kaudu (Näiteks Chrome).

Pange jooksma ka mõlemad APId:

  1. hs9-flask-api-raamatud - Port 5000
  2. hs9-flask-api-raamatute-otsing - Port 5001

Veebiliidese dünaamiliseks muutmine:

  • Raamatu loomine ja raamatutest otsimine olemasolevate HTML vormide kaudu juba töötab (kui API'd on käima pandud), aga hetkel ei ole veel loodud JavaSCript funktsioonid, mis tulemust meile veebilehel näitaks.
  • Implementeerime JavaScript failis listiraamatud() meetodi sisu:
    • Kutsume meetodi alguses välja GET päringu meie raamatute API vastu, mis kuulab päringuid localhost peal pordil 5000:
      • const responseData = await getDataAsJson("http://localhost:5000/raamatud/");
        • NB! responseData muutuja on JSON objekt, mille sees peaks olema REST API päringu vastus
    • Otsime üles HTML dokumendi elemendi ID väärtusega raamatud_result:
      • const resultElement = document.getElementById("raamatud_result");
    • Seame selle ploki väärtuseks tühja sõne:
      • resultElement.innerHTML = ""
    • Loome tsükkli, mis iga vastuses tagastatud raamatu ID kohta lisab raamatud_result HTML plokki uue lingi, mille kaudus aab raamatut alla laadida API'st:
      • resultElement.innerHTML = ""
        for (var raamat of responseData.raamatud){
        	resultElement.innerHTML += '<a href="http://localhost:5000/raamatud/'+raamat+'"  download="'+raamat+'.txt" >' +raamat+".txt</a> " +
        			'<a href="#" onclick="deleteObject(\'http://localhost:5000/raamatud/'+raamat+'\')" > [kustuta]</a>' +
        			"<br />";
        }
        • responseData.raamatud on API vastuse JSON element, milles on raamatu ID'de list.
        • Lisaks raamatute alla tõmbamise lingile, lisatakse ka raamatu kustutamise link. Selles lingis on JavaScript onClick sündmuse kuulaja, mis lingile vajutamisel kutsub välja deleteObject(raamatu_API_link) meetodi, mis hoolitseb raamatu kustutamise eest.

NB! See näite kood eeldab, et Azure'sse salvestatud failidel ei ole ".txt" laiendit!

  • Lahenduseks saate kas:
    1. Muuta JavaScript koodi, et ta eraldaks .txt failide nimede lõpust.
      • Näiteks saab raamatu faili nime jagada split('.') funktsiooni abil kaheks ning kasutada ainult esimest "poolt"
    2. Muuta Python API koodi, et ta ei lisaks .txt failide lõppu Azuresse üles laadides

Testige nüüd, kas raamatute alla tõmbamine ja kustutamine töötab!

  • Vigade korral saate uurida Flask API rakenduste/konteinerite väljundeid ning brauseri arenduskonsoolis (F12) näidatavaid JavaScript veateateid.
  • Selleks, et näha kas raamat kustutati või loodi, tuleb leheküljele refresh teha.
    • Parandame kustutamisege seotud olukorra sellega, et kutsume listiraamatud() meetodi välja JavaScript meetodi deleteObject lõpus
      • Lisage sinna rida: listiraamatud();
    • Parandame raamatu loomisega seotud olukorra:
      • Looge uus javaScript meetod handleResponse:
        • function handleResponse(form, responseData) {
          
          }
        • Lisage handleResponse meetodi väljakutse handleFormSubmit(event) funktsiooni sisse, enne rida } catch (error) {.
        • Lisage sinna rida: handleResponse(form, responseData);
          • Selle tulemusena käivitatakse handleResponse peale iga POST päringu tegemist (HTML vormi kaudu) ning saame sellese meedodisse kirjutada mis peaks juhtuma, kui saame POST päringu tulemuse kätte.
      • Implementeerime handleResponse meetodi sisu:
        • Lisame funktsiooni algusesse koodi mis otsib HTML dokumendist üles elemendi, kuhu saame kirjutada infot kasutajale, selle kohta kas POST päring õnnestus (raamatu loomine või raamatutest otsimine):
          • Lisage sinna: const resultElement = document.getElementById("tulemus");
        • Kui vormi (mis käivitati) id oli "frontform", siis loodi uus raamat. Siis kirjutame üle "tulemus" HTML ploki - paneme sinna vormi POST päringu JSON vastuse sisemise võtme "tulemus" väärtuse (API saadab sõnumi, et raamatu loomine õnnestus). Samuti uuendame raamatute nimekirja.
          • Lisage:
            if(form.id == "frontform"){
            	resultElement.innerHTML = responseData.tulemus;
            	listiraamatud();
            }
        • Kui vormi (mis käivitati) id oli "otsinguform", siis otsiti sõnet raamatute seest. Siis kirjutame üle "tulemus" HTML plokki - kirjutame sinna vormi POST päringu JSON vastuse sisemise võtme "tulemus väärtuse". Raamatute nimekirja ei ole vaja uuendada.
          • Lisage:
                if(form.id === "otsinguform"){
                    var output = "Sõne " + responseData.sone + " leiti järgmistest raamatutest:  <br/>"
            
                    for (var tulemus of responseData.tulemused) {
                        output += "Raamat " + tulemus.raamatu_id + " - " + tulemus.leitud + " korda! <br/>";
                    }
                    resultElement.innerHTML = output
                }

Ülesanne 10.3: Kasutajaliidese käivitamine konteineris.

Konteineriseerime meie poolt loodud kasutajaliidese.

  • Looge samase kausta Dockerfile järgneva sisuga:
    • FROM nginx:alpine
      
      COPY apiparingud.js /usr/share/nginx/html/apiparingud.js
      COPY front-end.html /usr/share/nginx/html/index.html
      
      EXPOSE 80
  • Ehitame Docker image hs10-front-end veebiliidese mikroteenuse jaoks:
    • docker build -t hs10-front-end -f Dockerfile .
  • Seda saab käima panna Dockeri konteinerina pordi 80 peal nii:
    • docker run -di -p 80:80 hs10-front-end

Testige, et õnnestub kõik kolm Docker conteinerit üles seada ning rakendust kasutada.

  1. hs10-front-end - port 80
  2. hs9-flask-api-raamatud - port 5000
  3. hs9-flask-api-raamatute-otsing - port 5001

Tulemus võiks olla midagi sellist:

Esitada: tehke ekraanivaated, mis näitavad et konteinerite jooksutamine õnnestus ning veebirakenduse kaudu õnnestub raamatuid luua, kustutada, nendest otsida ning neid alla laadida.

Boonus ülesanne: Veebiliidese muutmine, et see sisaldaks ka konkreetsest raamatust otsimise funktsionaalsust.

See ülesanne on täielikult iseseisev. Aga võite küsida vihjeid või abi vigade otsimisel.

Eesmärk:

  • Täiendage HTML faili, et sialdaks ka HTML form elemente konreetsest raamatust otsingu läbi viimiseks
    • Võib lisada ühe individuaalse HTML formi, või iga listitud raamatu juurde väikese form'i.
    • Lisage ka HTML blokk) kuhu hiljem panna päringu vastus, sarnaselet tavalisele raamatu otsingule
  • Täienedage javascript koodi, et läbi viia konkreetsest raamatust otsingu API kutse ja tulemuse lisamine HTML dokumenti.

Boonusülesande osas tuleb esitada:

  • Kood, mis sisaldab ka Dockerfile'i
  • Ekraanivaade veebiliidesest, mis näitab läbiviidud otsingu tulemust.

Lahenduse esitamine

Praktikumi lahendusena tuleb esitada:

  1. Veebiliidese mikroteenuse koodi projekti kaust koos Dockerfailiga
    • Ärge pange kaasa Python venv kaustasid!
  2. Ekraanivaated ülesandest 10.3
You must be logged in and registered to the course in order to submit solutions.

Võimalikud probleemid ja nende potentiaalsed lahendused.

  • Kui saate CORS veateate raamatute otsingu kohta:
    • Kontrollige, et raamatutest sõne otsingu meetodi raamatutest_sone_otsimine otspunkt ei lõppe / märgiga.
    • Peaks olema selliselt:
@app.route('/raamatu_otsing', methods = ['POST'])
def raamatutest_sone_otsimine():
  • Muidu võib tekkida lahkheli veebiliidese ja API vahel ja saab CORS veateate
  • Institute of Computer Science
  • Faculty of Science and Technology
  • University of Tartu
In case of technical problems or questions write to:

Contact the course organizers with the organizational and course content questions.
The proprietary copyrights of educational materials belong to the University of Tartu. The use of educational materials is permitted for the purposes and under the conditions provided for in the copyright law for the free use of a work. When using educational materials, the user is obligated to give credit to the author of the educational materials.
The use of educational materials for other purposes is allowed only with the prior written consent of the University of Tartu.
Terms of use for the Courses environment