# Web-ohjelmointi, syksy 2023 ## **KEHITYSBLOGI** --- ### Tekijä: Paula-Riitta Huttunen --- [ToC] ## Viikko 1 ### Mitä opin tällä viikolla? Aloitusviikolla sain palauteltua mieleen, kuinka Visual Studio Code toimii ja liityin kurssin Slack-ryhmään. Päivittelin ohjelmistoja koneeseeni ja latasin Node.js:n uusiksi. En oikeastaan oppinut vielä mitään uutta, lähinnä tuli vanhan kertausta, mikä oli toki ihan tarpeellista. ### Mitä harjoituksia tein? En vielä mitään (eipä tainnut edes olla mitään harjoituksia, vain sinne Slackiin rekisteröityminen), aika meni ihan puhtaasti luentojen kuunteluun ja perehtyen kurssimateriaaleihin sekä palauttaen mieleen kuinka VS Code ynnä sen yhteydessä tarvittavat lisäosat toimivat. Koitin myös hiukan palautella mieleen HMTL:n perusteita. --- ## Viikko 2 ### Mitä opin tällä viikolla? Tällä viikolla latasin ja konfiguroin Git:in ja perehdyin GitHubiin. Lisäksi palauttelin mieleen HTML:n perusteita. Git:iin uudelleen perehtymiseen ja gitin käyttövalmiiksi saattamiseen meni jonkun verran aikaa. Vaikka olin edellisessä työpaikassani käyttänyt gittiä, en kuitenkaan koskaan ollut aivan ymmärtänyt sen toimintaperiaatetta. Töissä ollessani oli Git käytännössä asennettu koneelleni puolestani ja minun tarvitsi vain osata käyttää graafistakäyttöliittymää (Git Extensions), jonka avulla tiedostoja "pullattiin", "pushattiin" ja "commitettiin", eikä minun tarvinnut ymmärtää mitä taustalla tapahtui. Nyt kun parin vuoden tauon jälkeen piti yrittää muistaa, mikä oli Git:in toimintalogiikka ja kuinka sillä operoitiin niin meni kyllä sormi suuhun. Git:iä asentaessa en meinannut ymmärtää kuinka luon SSH-avaimen ja yhdistän sen GitLabiin niin uppouduin sitten lukemaan Git:in opaskirjaa ja GitLabin ohjeita. -Osaan nyt luoda yksityisen ja julkisen SSH-avaimen (sekä komentokehotteen kautta OpenSSH:ta käyttäen että PuttyGen-ohjelman avulla) ja tiedän, että RSA:n sijaan kannattaa käyttää ed25519-salausta, ja että jos OpenSSH:sta on vanha versio niin tulee avainta luodessa käyttää "-o" -komentoa (selvisi, että minulla sittenkin oli OpenSSH, jota Windowseissa ei kuulema ole automaattisesti ja versioni oli riittävän tuore jottei tarvinnutkaan kikkailla). Opettajan ohjeisiin laittama linkki GitHubin sivuille ei toiminut niin en vielä saanut laitettua luomaani avainta sinne, mutta toivon osaavani laittaa sen sinne kunhan linkki päivitetään. Tällä viikolla opin myös paljon erilaisia käskyjä, joilla voi operoida Git Bash:issa ja luulen nyt ymmärtäväni aiempaa perusteellisemmin gitin toimintaperiaatetta. En usko enää palaavani käyttämään sitä graafistakäyttöliittymää, jota käytin töissä, koska sain nyt tietää sen olevan vajavaisempi toimintaominaisuuksiltansa verrattuna siihen, että syöttää käskyt suoraan komentokehotteeseen. ### Mitä harjoituksia tein? Tällä viikolla leijonan osan ajasta vei TRA1-kurssin tehtävät ja Git:in kanssa säätäminen, että olin siksi jäljessä luentojen kuuntelusta ja jälkijunassa tullessani missasin ensimmäisen harjoituksen palautuksen :( Haluan kuitenkin vielä tehdä sen, koska tarvitsen kertausta HTML:ään liittyvissä asioissa. Toivottavasti tehtävän saa vielä palauttaa myöhässäkin, vaikka en oleta saavani siitä enää mitään pisteitä. #### Harjoitus 1 Tämä oli HTML:ään liittyvä tehtävä, kopion opettajan pohjan ja tein siihen päälle omat muokkaukseni. Lopuksi ajoin HTML ja CSS-koodit validaattorissa. En löytänyt kuin yhden virheen, joka oli helppo korjata. Tehtävä näytti aluksi vaikeammalta kuin mitä se loppupelissä oli. --- ## Viikko 3 ### Mitä opin tällä viikolla? Ensimmäisenä opiskeluvuotenani aloitimme ohjelmoinnin perusteet TypeScriptillä, joten JavaScript oli toimintaperiaatteeltansa tuttu kieli, joskin pitkän tauon jälkeen tuntuu, että pitää jälleen aloittaa melkeinpä ihan perusteista. Viimeaikainen Javan kanssa operoiminen on onneksi helpottanut tiedon nopeaa omaksumista ja nyt hahmotan olioiden mekaniikkaa paremmin kuin aiemmin. ### Mitä harjoituksia tein? Tällä viikolla perehdyin vielä lisää JavaScriptiin ja tein kummatkin JS-aiheiset ohjelmointitehtävät; "*Javascript -perusteet, teht 1*" & "*Javascript -perusteet, teht 2*". Ne sujuivat odotettua mukavammin, mutta kyllä niissä silti riitti haasteita. Olin tyytyväinen, että sain kummatkin algoritmit lopulta toimimaan :) #### Harjoitus 2 ##### Javascript -perusteet, teht 1 Aloitin palindromifunktio-tehtävästä, joka sujuikin yllättävän hyvin, kun lopulta keksin miten vertaan taulukoiden alkioita keskenään. Jonkun verran meni aikaa palautellessa mieleen ihan ohjelmoinnin perustaitoja, kuten ehtolauseita sekä luuppien toimintaa. Onneksi meneillään olevan TRA1-kurssin Java-taitojen opettelun ohella on tullut kerrattua ihan ohjelmoinnin perusteitakin niin ei aivan nollasta ole tarvinnut aloittaa JS:n kanssa, ja asioiden omaksuminen on nopeampaa, kun on joku vertailukohta. Tässä tehtävässä palautui hyvin mieleen, kuinka sijoitetaan dataa listoihin ja verrataan keskenään listojen alkioita toisiinsa. ```javascript=16 function palindromi() { // kysytään syöte var input = require("readline-sync"); var nimi = input.question("Anna sana: "); // taulukoiden luonti const talsi = []; const kaannos = []; // muuttujien alustus let i = 0; let vastaus; // merkit syötetystä sanasta talteen for (i = 0; i < nimi.length; i++) { talsi.push(nimi[i]); // testitulostus //console.log("talsin testitulostus: " + talsi); } // sijoitetaan talsi-taulukon merkit lopusta alkuun kaannos-taulukkoon for (i = 0; i < talsi.length; i++) { kaannos[i] = talsi[talsi.length - 1 - i]; // testitulostus //console.log("käännoksen testitulostus: " + kaannos); } // taulukoiden vertaus loopin avulla for (i = 0; i < talsi.length; i++) { if (kaannos[i] == talsi[i]) { vastaus = true; } if (kaannos[i] != talsi[i]) { vastaus = false; } } return vastaus; } console.log("Annettu sana on palindromi: " + palindromi()); ``` --- #### Harjoitus 3 ##### Javascript -perusteet, teht 2 Harjoitus 3:ssa opettelin luomaan oliota sekä sijoittamaan luodut oliot taulukkoon. Aluksi oli hieman vaikeuksia saada luotua uusia olioita, mutta lopulta muistin miten JavaScriptissä käytetään luokkaa ja sen konstruktoria. Toisessa osassa tehtävää oli luotava funktio, joka etsii käyttäjän aiemmassa vaiheessa luotujen henkilöiden syötettyjä puhelinnumeroita aiemmin luodusta puhelinluettelosta. Toteutin tämän niin, että käyttäjältä jatkuvasti kysytään minkä toiminnon tämä haluaa suorittaa ja sitten toimintavaihtoehdot on listattu switch-rakenteeseen, jossa kutsutaan funktiota, joka joko suorittaa lisäyksen tai hakemisen tai sitten lopettaa ohjelman suorittamisen. ```javascript=16 /* Tee puhelinluettelo. Puhelinluetteloon lisäät taulukkoon objekteja (eli henkilöitä joilla nimi ja puhelinnumero). Käyttäjältä kysytään henkilön nimi ja puhelinnumero. Henkilön poisto -toimintoa ei tarvitse tässä versiossa olla. Tee hakutoiminto jossa haet nimen perusteella puhelinnumeron. Tee puhelinnumeron haku funktioksi. Funktion parametrina on taulukko josta haetaan henkilön nimi. Funktio palauttaa puhelinnumeron. Kutsu funktiota. Käyttöliittymän voit tehdä millaiseksi haluat (komentokehoite -pohjainen kuitenkin) */ // lukijan määrittäminen const lukija = require("readline-sync"); // muuttujan alustus var jatka = true; // luodaan puhelinluettelo-taulukko let puhelinluettelo = []; // Henkilo-luokan kontruktori class Henkilo { constructor(nimi, numero) { this.nimi = nimi; // uudelle oliolle olion parametrina nimi this.numero = numero; } } // funktio, joka kysyy käyttäjän tiedot ja luo niiden pohjalta henkilön, joka lisätään puhelinluetteloon function lisaaHenkilo() { let nimi = lukija.question("Anna nimi: "); let numero = lukija.question("Anna puhelinnumero: "); let henkilo = new Henkilo(nimi, numero); // luodaan uusi Henkilo-olio puhelinluettelo.push(henkilo); // lisätään luotu olio puhelinluetteloon } // funktio, jolla etsitään numero nimen perusteella function haeNumero() { let haettavaNimi = lukija.question("Anna haettavan nimi: "); for (let i = 0; i < puhelinluettelo.length; i++) { // käydään läpi puhelinluettelon oliot let henkilo = puhelinluettelo[i]; // jos arvot ja tyypit ovat samoja if (henkilo.nimi === haettavaNimi) { return henkilo.numero; // mikäli vastaavuus löytyi, palautetaan haettavan numero } } // muussa tapauksessa return "Etsittyä henkilöä ei löytynyt"; } // kysytään jatkuvasti mitä käyttäjä haluaa tehdä while (jatka) { let toiminto = lukija.question("Valitse toiminto (lisaa/hae/lopeta): "); // switch-rakenteella jatkotoimien selvittäminen switch (toiminto) { case "lisaa": lisaaHenkilo(); // lisätään Henkilo-olio puhelinluettelo-taulukkoon break; case "hae": console.log(haeNumero()); // haetaan numeroa nimen perusteella break; case "lopeta": jatka = false; // lopettaa ohjelman suorituksen break; default: console.log("Tuntematon toiminto."); } } ``` --- ## Viikko 4 ### Mitä opin tällä viikolla? Luokkien kanssa operointia; olioiden luomista luokasta ja luokan periytymistä. Luokat ja periytyminen on jo Java:sta tuttua, mutta se vaati vähän mieleen palauttelua. Luulin jo, että gitin kanssa operoiminen sujuisi kun olen sitä aiemminkin käyttänyt, mutta edellisestä kerrasta olikin sen verran aikaa, että sen kanssa vänkäämiseen kuluikin aika paljon aikaa. Toivon, että palautukseni onnistui ja palauttamani osoite päästää opettajan katsomaan ohjelmakoodiani. ### Mitä harjoituksia tein? #### Harjoitus 3 Suurimmat vaikeudet ovat tosiaan olleet git:in kanssa, en jostain syystä millään meinannut keksiä syytä siihen, miksi en saanut pushattua tiedostoa GitHubin repositoryyn. Terminaaliin tuli jatkuvasti jonkinlainen virheilmoitus, ilmeisesti liittyen johonkin merge-ongelmaan. En kyllä ymmärrä miten se oli mahdollista, kun repositorio oli olevinaan tyhjä, kun sinne yritin lisätä. No, oli siellä se README-tiedosto sekä lisenssi, olisivatko ne jotenkin voineet sekoittaa hommia...? Lopulta kuitenkin sain ongelman ratkaistuksi, en oikeastaan ole edes varma miksi onnistuin loppujen lopuksi. Pääasia on, että Henkilo.js -tiedoto on nyt Githubissa kansiossa Teht3. Toivon, että jatkossa gitin käyttö ei ole yhtä sekavaa ja hommat luistaa huomattavasti paremmin. Itse ohjelman kanssa ei ollut juuri ongelmia. Hieman päänvaivaa aiheutti Date()-metodin ymmärtäminen, jouduin siitä lukemaan jonkun verran ennen kuin ymmärsin sen toimintalogiikan. Huom! Harjoitus oli alunperin palautettu GitHubiin erilliseen repositoryyn (Henkilo.js, jossa oli kansio nimeltä Teht3, jossa oli tiedosto Henkilo.js), mutta kopioin kansion ja nimesin sen uudestaan tehtävänannon mukaisesti "Urheilija1" ja siirsin sen REST1-repostoryyn, jonne olen jakanut muutkin harjoitukset, jotka piti jakaa GitHubissa. ```javascript=16 /* Kehitystehtävänä on määritellä olio-ohjelmointikielille ominainen luokkamäärittely ja periytyminen JavaScript-kielellä. Määrittele yliluokka Henkilo, joka sisältää ihmisen henkilötietoja: etunimet, sukunimi, kutsumanimi, syntymävuosi. Määrittele luokka Urheilija, joka perii Henkilo-luokan ja toteuttaa lisäksi saantifunktiot (get- ja set-) Urheilija-luokalle merkityksellisiin attribuutteihin. Lisää Urheilija luokkaan seuraavat ominaisuudet: linkki kuvaan, omapaino, laji, saavutukset. Kirjoita nämä vaatimukset toteuttava koodi joka toimii node.js-tulkissa. Toteuta koodi. Lisää koodiin esimerkkejä Urheilija –olioista. Talleta toteutuksesi gitlab (tai github) -ympäristöön omaan projektiisi hakemistoon: Urheilu1 Kirjoita tehtävästä kommentointi ja huomioita kehittäjän blogiin (hackmd.io). */ class Henkilo { // alustetaan Henkilo-luokan omat yksityiset muuttujat #etunimi; #sukunimi; #kutsumanimi; #syntymaVuosi; // konstruktori Henkilo-luokalle constructor(etunimi, sukunimi, kutsumanimi, syntymaVuosi) { this.#etunimi = etunimi; this.#sukunimi = sukunimi; this.#kutsumanimi = kutsumanimi; this.#syntymaVuosi = new Date(syntymaVuosi, 0, 1); // asettaa päivämääräksi 1. tammikuuta parametrsissa saatuna vuonna } // **** getterit **** // getteri joka palauttaa syntymävuoden Date-objektin getFullYear()-metodilla get syntymaVuosi() { return this.#syntymaVuosi.getFullYear(); } get etunimi() { return this.#etunimi; } get sukunimi() { return this.#sukunimi; } get kutsumanimi() { return this.#kutsumanimi; } get syntymaVuosi() { return this.#syntymaVuosi.getFullYear(); } // *** setterit *** set etunimi(etunimi) { this.#etunimi = etunimi; } set sukunimi(sukunimi) { this.#sukunimi = sukunimi; } set kutsumanimi(kutsumanimi) { this.#kutsumanimi = kutsumanimi; } set syntymaVuosi(syntymaVuosi) { this.#syntymaVuosi = new Date(syntymaVuosi, 0, 1); } } // Urheilija-luokka laajentaa Henkilo-luokkaa (eli perii Henkilon ominaisuudet) class Urheilija extends Henkilo { // alustetaan Urheilija-olion omat yksityiset muuttujat #linkki_kuvaan; #omapaino; #laji; #saavutukset; // Urheilija-luokan konstruktori olion luomiseksi constructor( etunimi, sukunimi, kutsumanimi, syntymaVuosi, linkki_kuvaan, omapaino, laji, saavutukset ) { super(etunimi, sukunimi, kutsumanimi, syntymaVuosi); this.#linkki_kuvaan = linkki_kuvaan; this.#omapaino = omapaino; this.#laji = laji; this.#saavutukset = saavutukset; } // **** getterit **** get linkki_kuvaan() { return this.#linkki_kuvaan; } get omapaino() { return this.#omapaino; } get laji() { return this.#laji; } get saavutukset() { return this.#saavutukset; } // **** setterit **** set linkki_kuvaan(linkki_kuvaan) { this.#linkki_kuvaan = linkki_kuvaan; } set omapaino(omapaino) { this.#omapaino = omapaino; } set laji(laji) { this.#laji = laji; } set saavutukset(saavutukset) { this.#saavutukset = saavutukset; } } // Luodaan uusia Urheilija-olioita const Maija = new Urheilija( "Maija", "Meikäläinen", "Maija", 1990, "link_to_image", 60, "Jalkapallo", "SM-mitali 2019" ); const Matti = new Urheilija( "Matti", "Meikäläinen", "Matti", 1992, "link_to_image", 80, "Jääkiekko", "SM-mitali 2020" ); const Megan = new Urheilija( "Megan", "Rapinoe", "Megan", 1985, "https://upload.wikimedia.org/wikipedia/commons/thumb/3/37/Megancoupe2019.jpg/640px-Megancoupe2019.jpg", 60, "Jalkapallo", "Voittava maali vuonna 2008 sekä vuonna 2012 olympialaisten kultamitaliotteluissa" ); const Alexia = new Urheilija( "Alexia", "Putellas", "Alexia", 1994, "https://en.wikipedia.org/wiki/Alexia_Putellas#/media/File:Barcelona_femen%C3%AD_Medalla_d'Honor_del_Parlament_de_Catalunya_02_(Putellas_1).jpg", 56, "Jalkapallo", "FIFA Best Women’s Player -palkinnon voittaja vuonna 2022" ); const Mia = new Urheilija( "Mia", "Hamm", "Mia", 1972, "https://upload.wikimedia.org/wikipedia/commons/3/3e/Mia_Hamm_corner_%28cropped%29.jpg", 58, "Jalkapallo", "Kaksinkertainen olympiakultamitalisti, kaksinkertainen FIFA Naisten maailmancupin mestari" ); // Tulostetaan olioiden tiedot console.log( "Henkilön tiedot: " + Megan.etunimi + " " + Megan.sukunimi + " " + Megan.omapaino + " , " + "Saavutukset: " + Megan.saavutukset + " " + "Linkki kuvaan: " + " " + Megan.linkki_kuvaan ); console.log(" "); console.log("***********************"); console.log( "Henkilön tiedot: " + Alexia.etunimi + " " + Alexia.sukunimi + " " + Alexia.omapaino + " , " + "Saavutukset: " + Alexia.saavutukset + " " + "Linkki kuvaan: " + " " + Alexia.linkki_kuvaan ); console.log(" "); console.log("***********************"); console.log( "Henkilön tiedot: " + Mia.etunimi + " " + Mia.sukunimi + " " + Mia.omapaino + " , " + "Saavutukset: " + Mia.saavutukset + " " + "Linkki kuvaan: " + " " + Mia.linkki_kuvaan ); console.log(" "); console.log("***********************"); console.log(""); ``` --- ## Viikko 5 ja 6 ### Mitä opin näillä viikoilla? Viikkojen 5 ja 6 aikana perehdyttiin REST:iin ja RESTful API:ien luomiseen. Opettelimme myös AJAX:in, JQueryn ja Expressin käyttöä ja asensimme CORS-selainlaajennuksen sekä Postman-ohjelman, jonka avulla testasimme API-pyyntöjä. Käytin aika paljon aikaa näinä kahtena viikkona ymmärtääkseni mikä oikeastaan on API ja REST. Kävin lukuisia keskusteluja ChatGPT:n kanssa näiden kahden viikkojen aiheista, koska tunneilla tuli niin paljon asiaa niin lyhyen ajan sisällä, ettei sitä informaatiomäärää oikein pystynyt mitenkään käsittelemään ja tuntui, että kaikki käsitteet menivät sekaisin. Nyt koen, että ymmärrän paremmin, mutta luulen, että pitää vieläkin selkeyttää AJAX:in ja JQueryn toimintaperiaatteita, vaikka harjoituksissa 4a ja 4b harjoittelinkin niiden käyttöä. ### Mitä harjoituksia tein? Tein kummatkin harjoitustehtävät, jotka oli ajoitettu näille kahdelle viikolle. Harjoituksessa 4a oli tarkoitus luoda REST API sanakirjaa varten ja harjoituksessa 4b oli tarkoitus luoda tuohon luotuun sanakirja REST API:in käyttöliittymä. Eniten aikaa kului jälkimmäiseen tehtävään, yritin pitkään saada haluamani toiminnalisuudet toimimaan yhden index.html-dokumentin avulla, mutta lopulta päädyin jakamaan eri toiminnallisuudet omiksi .html-dokumenteiksi. #### Harjoitus 4a ##### REST API sanakirjaa varten Tässä harjoituksessa ei ollut juuri vaikeuksia, kun lopulta ymmärsin miten se REST-puoli tähän sanakirja API:iin toteutetaan. Toteutukseni on synkroninen, koska koin sen olevan helpompi toteuttaa (en tiedä olisiko se asynkroninen toteutus ollut juuri vaikeampi, mutta koin tämän tavan suoraviivaisemmaksi). Päätin tehdä sanankirjan luomiselle oman funktion, jota kutsutaan suorituksen alussa ja sitten siihen vain viitataan API-pyynnöissä. ```javascript=16 /* => Luo REST API sanakirjaa varten. Sanakirjassa (tieto tiedostossa - esim. sanakirja.txt) on taulukossa eri riveillä sana suomeksi ja englanniksi; esim. auto car talo house. Tarvitset API:a varten luoda hakua varten metodin (toteuta GET metodi) sekä sanojen lisäystä varten metodin (toteuta POST metodi). Tiedonhaussa parametrina on suomenkielinen sana. Haku palauttaa englannin kielisen sanan vastineen. Tiedonlisäyksessä tallennetaan suomenkielinen sana ja vastaava englanninkielinen sana uudelle riville (tekstitiedostoa kasvatetaan uudella rivillä). Tiedoston käsittelyä varten tarvitset fs moduulin ( require("fs")). Em. moduulista löytyy esim. metodi writeFileSync kirjoitusta varten ja readFileSync lukemista varten. (Tiedoston käsittely voi olla synkroninen tai asynkroninen - saa valita). => Talleta toteutuksesi gitlab (tai github) -ympäristöön omaan projektiisi hakemistoon: "REST1" => Kirjoita tehtävästä kommentointi ja huomioita kehittäjän blogiin (hackmd.io). */ const fs = require("fs"); const express = require("express"); var app = express(); // tehdään sovellus-olio express-kirjaston kautta app.use(express.json()); // käytetään json-muotoista dataa app.use(express.urlencoded({ extended: true })); // käytetään tiedonsiirrossa laajennettua muotoa, UTF8-merkistö // ***** (MITÄ SALLITAAN RESTapissa käytettävän) ****** // esiasetusten määrittely, CORS-määrittely // Add headers app.use(function (req, res, next) { // Website you wish to allow to connect res.setHeader("Access-Control-Allow-Origin", "*"); // Request methods you wish to allow res.setHeader( "Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE" ); // Request headers you wish to allow res.setHeader( "Access-Control-Allow-Headers", "Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token" ); // Set to true if you need the website to include cookies in the requests sent // to the API (e.g. in case you use sessions) res.setHeader("Access-Control-Allow-Credentials", true); res.setHeader("Content-type", "application/json"); // Pass to next layer of middleware next(); }); // ***************************************** /* luodaan funktio sanakirjan luomiseksi, jolla sanakirja voidaan ladata ilman, että täytyy jokaisessa vaiheessa luoda sanakirja uudestaan */ function lataaSanakirja() { const data = fs.readFileSync("./sanakirja.txt", { // luetaan data tekstitiedostosta encoding: "utf8", flag: "r", // määritellään, että tiedosto avataan lukemista varten }); const splitLines = data.split(/\r?\n/); // pilkkoo datan rivinvaihtomerkkien perusteella eri riveihin const sanakirja = []; // luodaan sanakirja-taulukko splitLines.forEach((line) => { // jokaisella rivillä... const sanat = line.split(" "); // split-metodin avulla annetaan sanat-muuttujalle arvoksi taulukko, jonka alkioiksi laitetaan jaettu rivi const sanapari = { fin: sanat[0], eng: sanat[1] }; // luodaan sanapari-objekti, jonka avain-arvo pareina on suomenkielinen sana (avain) ja englanninkielinen sana (arvo) sanakirja.push(sanapari); // sijoitetaan sanapari-objekti sanakirja-taulukkoon }); return sanakirja; } // ladataan sanakirja muistiin sovelluksen käynnistyessä let sanakirja = lataaSanakirja(); // ********************************************************************* // GET // näyttää sanakirjan app.get("/sanakirja", (req, res) => { res.json(sanakirja); // sanakirjan palautus }); // ********************************************************* // GET // sanojen etsiminen app.get("/searchword/:fin", (req, res) => { const fin = req.params.fin; // haetaan 'fin' parametrin arvo URL-osoitteesta const eng = sanakirja.find((sanapari) => sanapari.fin === fin); // etsii sanakirjasta syötettyä sanaa ja palauttaa englanninkielisen version res.json(eng ? { eng: eng.eng } : { message: "ei löydy!" }); // tämä on ehtolause ("ternary operator") lähettämään JSON-muotoinen vastaus HTTP-pyyntöön, mikäli englannin kielistä sanaa ei löydy }); // ************************************************* // POST // sanaparin lisääminen sanakirjaan app.post("/addword", (req, res) => { if (!req.body.fin || !req.body.eng) { // tarkistetaan, etteivät kentät ole tyhjiä ja että ne ovat ylippätänsä mukana res.status(400).json({ message: "Virheellinen pyyntö" }); // jos kentät ovat tyhjiä, nulleja tai määrittelemättömiä lähetetään virheilmoitus return; } const sanapari = req.body; // otetaan rungosta fin- ja eng-kentät ja sijoitetaan ne sanapari-objektiin sanakirja.push(sanapari); // lisätään sanapari sanakirja-taulukkoon fs.writeFileSync( "./sanakirja.txt", sanakirja.map((sanapari) => `${sanapari.fin} ${sanapari.eng}`).join("\n"), // lisätään sanapari halutussa muodossa tekstitiedostoon { encoding: "utf8", flag: "w" } // tiedostoon kirjoittamisen asetusten määrittäminen, w = write ); res.json(sanakirja); // vastauksena sanakirja JSON-muodossa HTTP-pyyntöön }); // *************************************************** // käynnistetään express-palvelin ja kuunnellaan porttia 3000 app.listen(3000, () => { console.log(`Serveri kuuntelee portissa 3000`); }); ``` ### Harjoitus 4b ##### REST APIiin käyttöliittymä, jonka avulla voi lisätä ja hakea sanoja Tässä harjoituksessa toteutin käyttöliittymän sanakirjalle. Tein html-pohjaisen käyttöliittymän, jossa jokainen toiminnallisuus (sanakirjan katsominen, sanaparin lisääminen ja sanan hakeminen) on toteutettu omana sivuna (omissa .html-tiedostoissa). Gittiin palautin myös alkuperäisen suunnitelmani käyttöliittymästä (sanakirjaUI.html), jota en kuitenkaan saanut toimimaan, ja tästä syystä päädyin tekemään omat sivut jokaiselle eri toiminnolle. Varsinaiseen ratkaisuuni kuuluvat siis seuraavat tiedostot: 1) index.html 2) view.html 3) add.html 4) search.html 5) sanakirja.txt Laitan tähän esimerkiksi vain index.html-tiedoston: ```javascript=16 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Sanakirjan pääsivu</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script> $(document).ready(function () { // Siirry "Näytä sanakirja" -sivulle $("#viewButton").click(function () { window.location.href = "view.html"; }); // Siirry "Lisää sana" -sivulle $("#addButton").click(function () { window.location.href = "add.html"; }); // Siirry "Hae sanaa" -sivulle $("#searchButton").click(function () { window.location.href = "search.html"; }); }); </script> <style> body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; background-color: #daa982; } button { padding: 10px 20px; margin: 10px; font-size: 16px; cursor: pointer; } </style> </head> <body> <h1>Sanakirja</h1> <button id="viewButton">Näytä sanakirja</button> <button id="addButton">Lisää sana</button> <button id="searchButton">Hae sanaa</button> </body> </html> ``` Tässä linkki GitHubiin, jonne tehtävä on palautettu: https://github.com/PaulaRii/REST1.git --- ## Viikko 7 ### Mitä opin tällä viikoilla? Viikon 7 aikana mm. perehdyimme tietokantojen toimintaan, Javascriptiin ja sen synkroniseen ja asynkroniseen suoritukseen, AJAX:iin sekä MVC:hen. Rinnakkaisuus sekä lupaukset käsitteenä olivat jo tuttuja Hajautetut järjestelmät -kurssilta, joskin niiden käyttäminen ei ollut itselle kovin selkeää, joten oli hyvä että niitä opeteltiin vielä tälläkin kurssilla. Generators, jolla kutsutaan useita alkioita kerralla ei sen sijaan ollut tuttu käsite. AJAX:iin perehtyminen vaati vielä omaa perehtymistä, koska se ei oikein kunnolla auennut luentojen aikana. ### Mitä harjoituksia tein? Tällä viikolla ei ollut palautettavaa harjoitusta. --- ## Viikko 8 ja 9 ### Mitä opin näillä viikoilla? Viikon 8 (luento 2.11.) aikana opettelimme tietokantasovelluksen tekoa. Teimme tunnilla yhdessä vanhan harjoitustehtävän, jossa luotiin tietokantasovellus. Asensimme MariaDB-ohjelman (minulla oli se jo valmiina, mutta olin unohtanut salasanani niin jouduin aika pitkään säätämään, ennen kuin sain HeidiSQL:ssä tietokannan auki. Onnistuin lopulta komentokehotteen kautta vaihtamaan uuden salasanan, kiitos ChatGPT:n ohjeiden!). Palauttelin mieleen miten SQL:n kanssa operoitiin ja miten HeidiSQL toimii. Viikolla 9 (luento 9.11.) käsittelimme REACT:ia, funktionaalisia komponentteja sekä tapahtumankäsitteliöitä (hooks). Opin ymmärtämään paremmin mitä tarkoittaa REACT ja miten tapahtumankäsittelijöillä operoidaan. ### Mitä harjoituksia tein? Tein harjoituksen 5, palautin sen paljon yli deadlinen (jäin useamman viikon jälkeen sairastelun takia), mutta sain tehtävän lopulta tehtyä ja palautin sen GitHubiin REST1-repositoryyn, johon olen jakanut oikeudet opettajalle. Yllättävän paljon aikaa meni pelkästään pohjakoodin luomiseen, vaikka seurasin huolellisesti opetusvideon ohjeistusta. Kuitenkin ilmeni erilaisia ongelmia, joiden ratkaisemiseen meni aika paljon aikaa. Lopulta kun olin saanut pohjan valmiiksi niin varsinaisen tehtävän tekemiseen (metodien lisäämisen REST APIin) ei kulunut kovin paljon aikaa. Testasin Postmanilla, että ratkaisuni varmasti toimii ja hyvinhän se toimi :) #### Harjoitus 5 En lisää tähän kaikkia tehtävään toteuttamiseen vaadittavaia koodejani, koska pitäisi lisätä useita tiedostoja, mutta listaan mihin kaikkiin tiedostoihin tein muutoksia/lisäyksiä, jotta sain PUT- ja DELETE-operaatiot toimimaan, ja laitan esimerkiksi pyyntöjen käsittelyyn tekemäni koodin tähän alle. Seuraavissa tiedostoissa on merkitty kommenteilla ne kohdat, joissa on omat lisäykseni: 1) controllers/postControllers.js 2) models/Post.js 3) routes/postRoutes.js: ```javascript=16 const express = require("express"); const postControllers = require("../controllers/postControllers"); const router = express.Router(); // @route GET && POST - /posts/ router .route("/") .get(postControllers.getAllPosts) .post(postControllers.createNewPost); // ************************** OMA OSUUS ******************************** // käsitellään GET, PUT ja DELETE -pyynnöt polussa /posts/:id router .route("/:id") .get(postControllers.getPostById) .put(postControllers.updateById) .delete(postControllers.deleteById); // ************************** OMA OSUUS LOPPUU *************************** module.exports = router; ``` Tässä vielä linkki GitHubiin, jonne tehtävä on palautettu: https://github.com/PaulaRii/REST1.git --- ## Viikko 10 ### Mitä opin tällä viikoilla? Viikon 10 aikana (luento 16.11.) opettelimme REACT:in käyttöä. Tällä viikolla oli suuria vaikuksia pysyä luennosta kärryillä ja palasin tallenteessa takaisin monia kertoja, kun en saanut toistettua omalla koneella stä mitä luennoitsija teki luennon aikana. Opin tällä viikolla lisää JSX:stä, webhookeista ja stateista. ### Mitä harjoituksia tein? Kävimme tunnilla läpi edellisen harjoitustehtävän, tällä viikolla ei ollut vielä uutta harjoitusta. --- ## Viikko 11 ### Mitä opin tällä viikoilla? Viikon 11 aikana (luento 23.11.) opeteltiin lisää hookkien käyttöä. Teimme tunnilla aiemmin tehdylle puhelinluettelolle Reactilla käyttöliittymän ja perehdyimme vähän myös Boostrappiin, jolla saa valmiita layoutteja. Vaikka koodin sai valmiiksi niin oli suuria ongelmia saada käyttöliittymä toimimaan, koska valmiissa pohjassa käytettiin vanhempaa react-route-versiota, minkä seurauksena jouduin aika paljon päivittämään pohjakoodia, jotta sain sen edes jotenkuten toimivaksi. Tuli jälleen kerrattua tietokannan luontia ja täytyi myös perehtyä reitittämiseen, joka yhä edelleen tuntuu aika monimutkaiselta aihekokonaisuudelta. Luennon lopuksi esiteltiin vähän Context API:a, jota on tarkoitus hyödyntää harjoitus 6:ssa, mutta minulle ei kyllä vielä yhtään auennut mikä se edes on. Täytynee pyytää ChatGPT:tä selittämään vähän tarkemmin, kun tunnilla konseptia ei juuri avattu. Toinen asia, johon olisin toivonut lisäopastusta tunneilla on Axios. Se mainittiin muutaman kerran, mutta sen toimintaa tai tarpeellisuutta ei oikeastaan ollenkaan selitetty. ### Mitä harjoituksia tein? Tälle viikolle ei ollut uutta harjoitusta, mutta meni aika paljon aikaa toteuttaamaan tunnilla yhdessä tehtyjä harjoituksia. Myös perehdyimme seuraaviin harjoitustehtäviin luomalla puhelinluettelo API:lle käyttölittymän Reactilla hyödyntäen Context API:a ja Bootstrappiä. --- ## Viikko 12 ### Mitä opin tällä viikoilla? Teimme luennolla yhdessä harjoitus 6:sta, jäin ihmettelemään miksi opettajalla ohjelma automaattisesti ehdottaa toista porttia, jos ehdotettu on toisessa käytössä, koska minulla se se ei ehdottanut. Jotta sain ohjelman toimimaan piti minun manuaalisesti muokata koodiini toinen portti (3001). Tällä viikolla en varsinaisesti oppinut mitään uutta, mutta syvennyin aiemmin opeteltuihin asioihin, kuten tietokantayhteyden toteuttamiseen, REST API:n luomiseen, Reactiin ja Context API:iin, joita nyt ymmärrän paremmin. Meni hyvin monta tuntia perehtyessä siihen miten toteutan harjoitus 6:sen. ### Mitä harjoituksia tein? Tein harjoituksen 6, ja käytin siihen varmasti enemmän aikaa kuin sen tekemiseen oli tarkoitettu käytettävän aikaa. Oli suuria ongelmia ymmärtää Context API:n käyttöä enkä meinannut saada Lisää, Muokkaa ja Poista -toiminnallisuuksia toimimaan, vaikka palvelimen puolella ne toimivat. Lopulta keksin, että minulla oli turhaan GlobalState.js-tiedosto sekoittamassa kuvioita ja kun poistin sen ja siihen kuuluvat context-tiedostot ja jätin vain PelaajatContext.js-tiedoston niin hommat ryhtyivät toimimaan paremmin. Ongelmia oli yhä poiston ja lisäyksen kanssa. Useiden tuntien ihmettelyn ja tuskailun jälkeen löysin virheen; olin palvelimen puolelle merkannut osoitteeksi "...urheilija/:id" ja käyttöliittymän puolelle "...urheilijat/:id". Useamman illan tuskailu ratkesi siis yhden kirjaimen poistamisella... Lopulta siis kaikki vaadittavat toiminnallisuudet toimivat. Kuvia en yrityksestäni huolimatta valitettavasti saanut näkymään urheilija-näkymässä. Käyttöliittymäni idea on siis siinä, että taulukkoon voi lisätä urheilijoita painamalla etusivulla olevaa "Lisää urheilija"-painiketta ja urheilijoiden tietoja pääsee katsomaan ja muokkaamaan klikkaamalla urheilijan sukunimeä. Tällöin aukeaa näkymä sivun alareunaan. Näkymässä voi myös poistaa urheilijan. Muokkaus-painikkeella pääsee samanlaiseen ikkunaan kuin lisäys-painikkeella. Taulukon otsikko päivittyy sitä mukaan kun tietuemäärä taulussa muuttuu. Käytin ratkaisussani sekä Context API:a komponenttien kanssa että Bootstrappia muotoiluun (taulukko, painikkeet, näkymä ja lisäys- sekä muokkaussivu). #### Harjoitus Tässä linkki GitHubiin, jonne tehtävä on palautettu: https://github.com/PaulaRii/REST1.git **Huom!** Tietokannan luontiskripti on Urheilija2/serveri-kansion sisällä tekstitiedostona. --- ## Viikko 13 ### Mitä opin tällä viikoilla? Tällä viikolla perehdyimme automatisoituun testaamiseen. Mieleeni jäi erityisesti yksikkötestaaminen. ### Mitä harjoituksia tein? Tein viimeisen harjoituksen (harjoitus 7) kevään aikana. Sen kanssa ei ollut suuresti ongelmia, sen tekeminen vain vei paljon aikaa. Yksi ärsyttävä ongelma oli kylläkin käytttämässäni valmiissa bootstrap-pohjassa; siinä oli jokin .pug-tiedosto, jollaisesta ei oltu mielestäni puhuttu kurssin aikana. Se aiheutti ongelmia, koska index.html-tiedostoon koostamani sivunrakenne piti muuttaa tuohon pug-tiedoston muotoon tai muuten muutokset eivät tallentuneet jostain käsittämättömästä syystä. Kerran jo menetin tekemäni koodin ja minun piti aloittaa alusta. Jostain syystä kun projektin avaa uudestaan sen kerran suljettua niin index.html muuttuu index.pug-tiedoston mukaiseksi. Onneksi ChatGPT osasi auttaa sen index.pug-tiedoston luomisessa, koska sen käytön opetteluun ei ollut enää aikaa. Nyt jälkiviisaana tuli mieleen, että sen index.pug-tiedoston olisi varmaan vaan voinut poistaa koko projektista...? #### Harjoitus ```javascript=16 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <meta name="description" content="" /> <meta name="author" content="" /> <title>Portfolio - Harjoitus 7</title> <link rel="icon" type="image/x-icon" href="assets/img/profiilikuva_uusi2.jpg" /> <!-- Font Awesome icons (free version)--> <script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous" ></script> <!-- Google fonts--> <link href="https://fonts.googleapis.com/css?family=Saira+Extra+Condensed:500,700" rel="stylesheet" type="text/css" /> <link href="https://fonts.googleapis.com/css?family=Muli:400,400i,800,800i" rel="stylesheet" type="text/css" /> <!-- Core theme CSS (includes Bootstrap)--> <link href="css/styles.css" rel="stylesheet" /> </head> <body id="page-top"> <!-- Navigation--> <nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top" id="sideNav" > <a class="navbar-brand js-scroll-trigger" href="#page-top"> <span class="d-block d-lg-none">Paula-Riitta Huttunen</span> <span class="d-none d-lg-block"> <img class="img-fluid img-profile rounded-circle mx-auto mb-2" src="assets/img/profiilikuva_uusi2.jpg" alt="Profiilikuva" /> </span> </a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation" > <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarResponsive"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link js-scroll-trigger" href="#about" >Home</a > </li> <li class="nav-item"> <a class="nav-link js-scroll-trigger" href="#experience" >Harjoitukset</a > <ul> <li> <a class="nav-link js-scroll-trigger" href="#harjoitus-0" >Harjoitus 0</a > </li> <li> <a class="nav-link js-scroll-trigger" href="#harjoitus-1" >Harjoitus 1</a > </li> <li> <a class="nav-link js-scroll-trigger" href="#harjoitus-2" >Harjoitus 2</a > </li> <li> <a class="nav-link js-scroll-trigger" href="#harjoitus-3" >Harjoitus 3</a > </li> <li> <a class="nav-link js-scroll-trigger" href="#harjoitus-4a" >Harjoitus 4a</a > </li> <li> <a class="nav-link js-scroll-trigger" href="#harjoitus-4b" >Harjoitus 4b</a > </li> <li> <a class="nav-link js-scroll-trigger" href="#harjoitus-5" >Harjoitus 5</a > </li> <li> <a class="nav-link js-scroll-trigger" href="#harjoitus-6" >Harjoitus 6</a > </li> <li> <a class="nav-link js-scroll-trigger" href="#harjoitus-7" >Harjoitus 7</a > </li> </ul> </li> <li class="nav-item"> <a class="nav-link js-scroll-trigger" href="#education" >Palauteosio</a > </li> </ul> </div> </nav> <!-- Page Content--> <div class="container-fluid p-0"> <!-- About--> <section class="resume-section" id="about"> <div class="resume-section-content"> <h1 class="mb-0"> Paula-Riitta <span class="text-primary">Huttunen</span> </h1> <div class="subheading mb-5"> Itä-Suomen Yliopisto · tietojenkäsittelytiede · <a href="mailto:paularii@uef.fi">paularii@uef.fi</a> </div> <p class="lead mb-5"> Tämä on Web-ohjelmoinnin kurssia varten tehty portfolio, johon koostettu kuvaukset kurssilla tekemistäni harjoitustöistä ja lisäksi siihen on sisällytetty palauteosio. </p> <div class="social-icons"> <a class="social-icon" href="https://www.linkedin.com/in/paula-riitta-huttunen/" > <i class="fab fa-linkedin-in"></i> </a> <a class="social-icon" href="https://github.com/PaulaRii" > <i class="fab fa-github"></i> </a> <a class="social-icon" href="https://twitter.com/Lydiitti" > <i class="fab fa-twitter"></i> </a> </div> </div> </section> <hr class="m-0" /> <!-- Experience--> <section class="resume-section" id="experience"> <div class="resume-section-content"> <h2 class="mb-5">Harjoitukset</h2> <div class="d-flex flex-column flex-md-row justify-content-between mb-5" id="harjoitus-0" > <div class="flex-grow-1"> <h3 class="mb-0">Harjoitus 0</h3> <div class="subheading mb-3"> HTML-koodin korjaaminen </div> <p> Tämä oli HTML:ään liittyvä tehtävä, jossa kopion opettajan pohjan ja tein siihen päälle omat muokkaukseni. Lopuksi ajoin HTML ja CSS-koodit validaattorissa. En löytänyt kuin yhden virheen, joka oli helppo korjata. Tehtävä näytti aluksi vaikeammalta kuin mitä se loppupelissä oli. </p> </div> <div class="flex-shrink-0"> <span class="text-primary">Viikko 2</span> </div> </div> <div class="d-flex flex-column flex-md-row justify-content-between mb-5" id="harjoitus-1" > <div class="flex-grow-1"> <h3 class="mb-0">Harjoitus 1</h3> <div class="subheading mb-3"> Javascript -perusteet 1 </div> <p> Harjoituksessa 1 toteutin palindromifunktion, joka tarkistaa, onko annettu merkkijono palindromi. Käytin JavaScriptin listoja ja luuppeja sekä ehtolauseita vertaillakseni merkkijonon alkioita toisiinsa. Koodi koostui seuraavista vaiheista: </p> <p> 1. Syötteen kysyminen käyttäjältä readline-sync -kirjastolla.<br /> 2. Merkkien tallentaminen syötetystä sanasta taulukkoon.<br /> 3. Taulukon kääntäminen sijoittamalla alkuperäisen taulukon merkit lopusta alkuun uuteen taulukkoon.<br /> 4. Alkuperäisen ja käännetyn taulukon merkkien vertailu toisiinsa luupin avulla.<br /> 5. Vertailun tuloksen palauttaminen totuusarvona. </p> <p> Harjoituksen tavoitteena oli harjoitella ohjelmoinnin perusteita, erityisesti ehtolauseiden ja luuppien käyttöä, sekä vahvistaa JavaScript-osaamistani. Tämä harjoitus oli hyvä kertausharjoitus, joka auttoi palauttamaan mieleen ohjelmoinnin perustaitoja. </p> <p> Harjoituksen aikana palautui hyvin mieleen, kuinka sijoitetaan dataa listoihin ja verrataan keskenään listojen alkioita toisiinsa. Opin myös paremmin käsittelemään merkkijonoja sekä listoja JavaScriptissä. Vaikka tämä harjoitus auttoikin kertaamaan perusasioita, koen, että lisäharjoitus olisi ehkä tarpeen, erityisesti monimutkaisempien algoritmien ja tietorakenteiden osalta. </p> <p> Mielestäni onnistuin harjoituksessa ihan hyvin, sillä sain palindromifunktion toimimaan. Jos tekisin tehtävän uudelleen, kiinnittäisin enemmän huomiota tarkemmin tehtävänantoon (jotta teen juuri sitä mitä pyydettiin) sekä koodin optimointiin ja tehokkuuteen, esimerkiksi käyttämällä jotain tehokkaampia vertailu- ja käsittelytapoja. </p> <p>Linkki vastaukseen HackMD:ssä:</p> <a href="https://hackmd.io/@PaulaH/SsH20JNSf411" >https://hackmd.io/@PaulaH/SsH20JNSf411</a > </div> <div class="flex-shrink-0"> <span class="text-primary">Viikko 3</span> </div> </div> <div class="d-flex flex-column flex-md-row justify-content-between mb-5" id="harjoitus-2" > <div class="flex-grow-1"> <h3 class="mb-0">Harjoitus 2</h3> <div class="subheading mb-3"> Javascript -perusteet 2 </div> <p> Harjoituksessa 2 opettelin luomaan oliota sekä sijoittamaan luodut oliot taulukkoon. Aluksi oli hieman vaikeuksia saada luotua uusia olioita, mutta lopulta muistin miten JavaScriptissä käytetään luokkaa ja sen konstruktoria. </p> <p> Toisessa osassa harjoitusta oli luotava funktio, joka etsii käyttäjän aiemmassa vaiheessa luotujen henkilöiden syötettyjä puhelinnumeroita aiemmin luodusta puhelinluettelosta. Toteutin tämän niin, että käyttäjältä jatkuvasti kysytään minkä toiminnon tämä haluaa suorittaa ja sitten toimintavaihtoehdot on listattu switch-rakenteeseen, jossa kutsutaan funktiota, joka joko suorittaa lisäyksen tai hakemisen tai sitten lopettaa ohjelman suorittamisen. </p> <p> Harjoituksessa 2 toteutin puhelinluettelo-ohjelman, jossa käyttäjä voi lisätä henkilöitä nimellä ja puhelinnumerolla, sekä hakea henkilöiden puhelinnumeroita nimellä. Koodi koostui seuraavista vaiheista: </p> <p> 1. Syötteen kysyminen käyttäjältä readline-sync -kirjastolla.<br /> 2. Henkilön tietojen tallentaminen oliona puhelinluettelo-taulukkoon.<br /> 3. Olion luominen Henkilo-luokasta käyttäen sen konstruktoria.<br /> 4. Olioiden lisääminen puhelinluettelo-taulukkoon.<br /> 5. Funktio, joka hakee puhelinnumeron syötetyn nimen perusteella.<br /> 6. Käyttäjän jatkuva syötteen kysyminen ja toiminnan suorittaminen switch-rakenteen avulla. </p> <p> Harjoitusen tavoitteena oli harjoitella oliopohjaista ohjelmointia JavaScriptissä, erityisesti luokkien ja konstruktorien käyttöä, sekä vahvistaa taitoja käsitellä taulukoita ja funktioita. Tämä harjoitus auttoi ymmärtämään ohjelmoinnin peruskonsepteja ja oli hyvää kertausta olio-ohjelmoinnin perusteista. </p> <p> Harjoituksen aikana kertasin kuinka luodaan ja käytetään olioita sekä operoidaan taulukoiden ja merkkijonojen kanssa JavaScriptissä. Harjoitus auttoi myös ymmärtämään paremmin funktioiden käyttöä ja niiden parametrisointia. </p> <p> Mielestäni onnistuin harjoituksessa hyvin, sillä sain puhelinluettelo-ohjelman toimimaan oikein ja kaikki vaaditut toiminnallisuudet toteutettua. Ei tule mieleen mitä olisi kannattanut tehdä toisin. </p> <p>Linkki vastaukseen HackMD:ssä:</p> <a href="https://hackmd.io/@PaulaH/SsH20JNSf411" >https://hackmd.io/@PaulaH/SsH20JNSf411</a > </div> <div class="flex-shrink-0"> <span class="text-primary">Viikko 3</span> </div> </div> <div class="d-flex flex-column flex-md-row justify-content-between mb-5" id="harjoitus-3" > <div class="flex-grow-1"> <h3 class="mb-0">Harjoitus 3</h3> <div class="subheading mb-3"> JavaScript -perusteet 3: Luokat ja periytyminen </div> <p> Harjoituksessa 3 opettelin luokkien määrittelyä ja periytymistä JavaScriptissä. Vaikka konsepti oli ennestään tuttu Java-kielestä, tarvitsin hieman kertausta. </p> <p> Suurin haaste oli Git-versionhallinnan kanssa. Yritin pushata tiedostoa GitHub-repositorioon, mutta kohtasin jatkuvasti virheilmoituksia, jotka liittyivät mahdollisesti merge-ongelmiin. Lopulta sain ongelman ratkaistua, vaikka en olekaan ihan varma, mikä lopulta auttoi ratkaisemaan ongelman. </p> <p> Itse ohjelmointitehtävässä ei ollut suurempia ongelmia, mutta Date-metodin toimintalogiikan ymmärtäminen vaati hieman lisäopiskelua. </p> <p> Harjoituksessa 3 toteutin Henkilo-luokan ja siitä periytyvän Urheilija-luokan. Urheilija-luokassa määriteltiin get- ja set-funktiot erityisille attribuuteille. Koodi koostui seuraavista vaiheista: </p> <p> 1. Henkilo-luokan määrittely ja konstruktorin luominen.<br /> 2. Henkilo-luokan getter- ja setter-metodien määrittely.<br /> 3. Urheilija-luokan määrittely, joka perii Henkilo-luokan.<br /> 4. Urheilija-luokan omien ominaisuuksien ja metodien määrittely.<br /> 5. Urheilija-olioiden luominen ja niiden tietojen tulostaminen. </p> <p> Harjoitusta tehdessä syvensin ymmärrystäni olio-ohjelmoinnista, erityisesti luokkien ja periytymisen osalta. Tämä harjoitus vahvisti lisää JavaScript-taitojani ja oli hyvää kertausta olio-ohjelmoinnin perusteista. </p> <p> Harjoituksen aikana opin lisää luokkien määrittelystä ja periytymisestä JavaScriptissä. Tämä harjoitus auttoi myös ymmärtämään paremmin getter- ja setter-metodien käyttöä. Ei tule mieleen mitä jäi oppimatta. </p> <p> Mielestäni onnistuin tehtävässä ihan hyvin, sillä sain toteutettua kaikki vaaditut toiminnallisuudet ja koodini toimii oikein. Jos tekisin tehtävän uudelleen, kiinnittäisin enemmän huomiota Git-versionhallinnan käyttöön, ettei olisi niin paljon ongelmia sen kanssa. </p> <p> <strong>Huom! </strong>Harjoitus oli alunperin palautettu GitHubiin erilliseen repositoryyn (Henkilo.js, jossa oli kansio nimeltä Teht3, jossa oli tiedosto Henkilo.js), mutta kopioin kansion ja nimesin sen uudestaan tehtävänannon mukaisesti "Urheilija1" ja siirsin sen REST1-repostoryyn, jonne olen jakanut muutkin harjoitukset, jotka piti jakaa GitHubissa. Tässä linkki päivitettyyn sijaintiin REST1-repositoryyn: </p> <a href="https://github.com/PaulaRii/REST1.git" >https://github.com/PaulaRii/REST1.git</a > </div> <div class="flex-shrink-0"> <span class="text-primary">Viikko 4</span> </div> </div> <div class="d-flex flex-column flex-md-row justify-content-between mb-5" id="harjoitus-4a" > <div class="flex-grow-1"> <h3 class="mb-0">Harjoitus 4a</h3> <div class="subheading mb-3"> Sanakirja REST API </div> <p> Harjoituksessa 4a luotiin REST API sanakirjaa varten. Sanakirjassa jokainen rivi sisältää suomenkielisen sanan ja sen englanninkielisen vastineen. Toteutin tehtävän synkronisena, koska koin sen olevan helpompi toteuttaa. </p> <p> REST API:n toteutus koostui seuraavista vaiheista: </p> <p> 1. Express-sovellusolion luominen.<br /> 2. CORS- ja esiasetusten määrittely API-pyynnöille.<br /> 3. Sanakirjan lataaminen tekstitiedostosta sovelluksen käynnistyessä.<br /> 4. GET-metodin toteutus koko sanakirjan palauttamiseksi.<br /> 5. GET-metodin toteutus sanojen etsimiseksi suomenkielisen sanan perusteella.<br /> 6. POST-metodin toteutus uusien sanaparien lisäämiseksi sanakirjaan ja tekstitiedostoon. </p> <p> Harjoituksen tavoitteena oli syventää ymmärrystä REST API:n toiminnasta ja Expressin käytöstä. Tämä harjoitus auttoi hahmottamaan paremmin, miten API-pyyntöjä käsitellään ja miten tiedostoja käsitellään Node.js:ssä. </p> <p> Tehtävän aikana opin enemmän REST API:sta ja Expressin käytöstä, sekä tiedostojen käsittelystä Node.js:ssä. Tämä harjoitus oli hyödyllinen johdatus API-kehitykseen ja auttoi ymmärtämään REST-arkkitehtuurin periaatteita. </p> <p> Harjoitus onnistui hyvin, sillä sain API:n toimimaan oikein ja kaikki vaaditut toiminnallisuudet toteutettua. Jos tekisin tehtävän uudelleen, harkitsisin asynkronisen toteutuksen käyttämistä parantaakseni sovelluksen suorituskykyä. </p> <p>Linkki vastaukseen GitHubissa:</p> <a href="https://github.com/PaulaRii/REST1" >https://github.com/PaulaRii/REST1</a > </div> <div class="flex-shrink-0"> <span class="text-primary">Viikko 5</span> </div> </div> <div class="d-flex flex-column flex-md-row justify-content-between mb-5" id="harjoitus-4b" > <div class="flex-grow-1"> <h3 class="mb-0">Harjoitus 4b</h3> <div class="subheading mb-3"> Sanakirja REST API -käyttöliittymä </div> <p> Harjoituksessa 4b luotiin käyttöliittymä aiemmin toteutettuun sanakirja REST APIin. Käyttöliittymän avulla voi lisätä ja hakea sanoja. Toteutin käyttöliittymän HTML:n ja jQueryn avulla, ja jaoin toiminnallisuudet eri sivuille. </p> <p> Käyttöliittymän toteutus koostui seuraavista vaiheista: </p> <p> 1. HTML-sivujen luominen eri toiminnallisuuksille: <strong >index.html, view.html, add.html, search.html</strong >.<br /> 2. jQueryn käyttö lomakkeiden käsittelyyn ja API-pyyntöjen lähettämiseen.<br /> 3. CORS-otsikoiden lisääminen REST APIin, jotta käyttöliittymä voi tehdä pyyntöjä palvelimelle.<br /> 4. Sanakirjan tietojen hakeminen ja näyttäminen <strong>view.html</strong>-sivulla.<br /> 5. Uuden sanaparin lisääminen <strong>add.html</strong>-sivun lomakkeella.<br /> 6. Suomenkielisen sanan hakeminen ja sen englanninkielisen vastineen näyttäminen <strong>search.html</strong>-sivulla. </p> <p> Harjoituksen tavoitteena oli syventää ymmärrystä käyttöliittymien luomisesta REST API:a hyödyntäen. Tämä harjoitus auttoi ymmärtämään paremmin jQueryn käyttöä ja API-pyyntöjen käsittelyä. </p> <p> Harjoitusta tehdessä opin jQueryn käyttöä ja ymmärsin paremmin REST API -käyttöliittymien toteuttamista. Tämä harjoitus oli hyödyllinen johdatus API-kehitykseen ja auttoi ymmärtämään, miten käyttöliittymä ja API kommunikoivat keskenään. </p> <p> Harjoitus onnistui ihan hyvin, sain käyttöliittymän toimimaan ja kaikki vaaditut toiminnallisuudet toteutettua. Jos tekisin tehtävän uudelleen, toteuttaisin ehkä käyttöliittymän yksinkertaisemmin yhdelle sivulle, jotta käytettävyys olisi selkempää. </p> <p>Linkki vastaukseen GitHubissa:</p> <a href="https://github.com/PaulaRii/REST1" >https://github.com/PaulaRii/REST1</a > </div> <div class="flex-shrink-0"> <span class="text-primary">Viikko 5 ja 6</span> </div> </div> <div class="d-flex flex-column flex-md-row justify-content-between mb-5" id="harjoitus-5" > <div class="flex-grow-1"> <h3 class="mb-0">Harjoitus 5</h3> <div class="subheading mb-3"> Node-Express-starter </div> <p> Harjoituksessa 5 luotiin Node.js REST API, joka käyttää Expressiä ja MariaDB:tä. Tavoitteena oli lisätä pohjakoodiin REST-rajapinnan mukaiset metodit PUT ja DELETE tietyn id:n perusteella kenttien "title" ja "body" päivittämiseksi ja tietueen poistamiseksi. </p> <p> REST API:n toteutus koostui seuraavista vaiheista: </p> <p> 1. MariaDB:n kanssa taistelu ja tietokannan luominen.<br /> 2. Pohjakoodin kopioiminen.<br /> 3. PUT- ja DELETE-metodien lisääminen REST API:iin pohjakoodin mukaisesti.<br /> 4. API:n testaaminen Postmanilla kaikkien operaatioiden varmistamiseksi (GET, POST, PUT, DELETE). </p> <p> Seuraavissa tiedostoissa tein muutoksia PUT- ja DELETE-metodien lisäämiseksi: </p> <ul> <li>controllers/postControllers.js</li> <li>models/Post.js</li> <li>routes/postRoutes.js</li> </ul> <p> Tämä harjoitus auttoi ymmärtämään paremmin Node.js:n ja MariaDB:n käyttöä REST API:n kanssa. Opin erityisesti, miten tietokannan operaatioita (kuten haku, lisäys, päivitys ja poisto) voidaan toteuttaa API:n kautta ja miten testata niitä Postmanilla. </p> <p> Alkuvaikeuksista huolimatta harjoitus onnistui lopulta hyvin, sillä sain kaikki vaaditut toiminnallisuudet toimimaan. Varmasti tämän olisi voinut tehdä jotenkin paremminkin, mutta en tiedä mitä tekisin toisin, jos tekisin harjoituksen uudestaan. </p> <p>Linkki vastaukseen GitHubissa:</p> <a href="https://github.com/PaulaRii/REST1" >https://github.com/PaulaRii/REST1</a > </div> <div class="flex-shrink-0"> <span class="text-primary">Joulukuu</span> </div> </div> <div class="d-flex flex-column flex-md-row justify-content-between mb-5" id="harjoitus-6" > <div class="flex-grow-1"> <h3 class="mb-0">Harjoitus 6</h3> <div class="subheading mb-3"> Urheilija II (REST API & React-sovellus) </div> <p> Harjoituksessa 6 toteutettiin JavaScript-palvelinsovellus, joka tarjoaa REST-rajapinnan kautta tiedon urheilijoista. Tavoitteena oli toteuttaa datan haku, lisäys, poisto ja päivitys MariaDB-tietokantaan sekä luoda React-käyttöliittymä, jonka avulla näitä operaatioita voi suorittaa. </p> <p> REST API:n ja React-käyttöliittymän toteutus koostui seuraavista vaiheista: </p> <p> 1. Tietokannan luominen MariaDB:llä.<br /> 2. REST-rajapinnan toteuttaminen Expressin avulla.<br /> 3. CRUD (Create, Read, Update, Delete) -operaatioiden toteutus tietokantaan.<br /> 4. React-sovelluksen luominen ja Context API:n hyödyntäminen datan hallinnassa.<br /> 5. Bootstrapin käyttö käyttöliittymän muotoilussa. </p> <p> Palvelinpuolen koodissa hyödynsin seuraavia tiedostoja: </p> <ul> <li>index.js</li> </ul> <p>React-käyttöliittymän tärkeimmät komponentit:</p> <ul> <li>App.js</li> <li>PelaajaContext.js</li> <li>PelaajaLista.js</li> <li>LisaaPelaaja.js</li> <li>MuokkaaPelaaja.js</li> <li>PelaajaTiedotNakyma.js</li> <li>PoistaPelaaja.js</li> </ul> <p> Tämä harjoitus syvensi ymmärrystäni REST API:n luomisesta ja Reactin käytöstä tietokantasovelluksen rakentamisessa. Pitkällisen selvittelyn jälkeen koin myös oppivani Context API:n hyödyntämistä datan hallinnassa. </p> <p> Harjoitus onnistui lopulta melko hyvin, vaikka kohtasin aluksi paljon haasteita, erityisesti Context API:n käytössä ja React-komponenttien hallinnassa. Lopputuloksena oli kuitenkin toimiva sovellus, joka mahdollistaa urheilijoiden tietojen hallinnan (lisäys, tarkastelu, muookaus ja poisto). Jostain syystä en saanut kuvia näkymään ja pitkän ja piinallisen yrittämisen jälkeen luovuin kuvien lisäämisestä. Jos tekisin harjoituksen uudelleen, selvittäisin miten kuvat saa näkymään. Perehtyisin myös vielä lisää siihen Context API:n toimintaan. </p> <p>Linkki vastaukseen GitHubissa:</p> <a href="https://github.com/PaulaRii/REST1" >https://github.com/PaulaRii/REST1</a > <p> <strong>Huom!</strong> Tietokannan luontiskripti on Urheilija2/serveri-kansion sisällä tekstitiedostona. </p> </div> <div class="flex-shrink-0"> <span class="text-primary">Joulukuu</span> </div> </div> <div class="d-flex flex-column flex-md-row justify-content-between mb-5" id="harjoitus-7" > <div class="flex-grow-1"> <h3 class="mb-0">Harjoitus 7</h3> <div class="subheading mb-3">e-Portfolio</div> <p> Viimeisessä harjoituksessa koostin e-portfolion, jossa on mahdollista navigoida aiemmin toteuttamieni tehtävien sisällä. Käytin erityisesti Bootstrap-komponentteja hyödyntämällä valmista Bootstrap-pohjaa, mikä helpotti rakenteen luomista ja sisällön lisäämistä. </p> <p> Vaikka harjoitus ei ollut erityisen vaikea, se vei aikaa. Ainoa varsinainen haaste oli valmiissa Bootstrap-pohjassa ollut .pug-tiedosto, joka aiheutti harmaita hiuksia, koska muutokset index.html-tiedostoon eivät jostain syystä tallentuneet oikein ilman sen muokkaamista. Onneksi ChatGPT auttoi .pug-tiedoston luomisessa, vaikka näin jälkikäteen ajateltuna sen poistaminen olisi voinut olla helpompi ratkaisu. </p> <p> Harjoituksen tavoitteena oli koota aiemmat tehtävät selkeästi navigoitavaksi portfolioksi ja harjoitella Bootstrapin käyttöä web-sivuston rakentamisessa. Tämä auttoi ymmärtämään paremmin Bootstrap-komponenttien hyödyntämistä ja sivuston rakenteen suunnittelua. </p> <p> Opin paljon Bootstrapin käytöstä ja sen tarjoamista valmiista komponenteista, jotka helpottivat sivuston rakenteen luomista. Sain myös kokemusta siitä, kuinka valmiita pohjia voidaan mukauttaa omiin tarpeisiin sopiviksi. Vaikka .pug-tiedoston käsittely aiheutti haasteita, onnistuin lopulta luomaan toimivan portfolion. </p> <p> Mielestäni onnistuin e-portfolion toteuttamisessa hyvin, sillä lopullinen portfolio on selkeä ja toimiva. Jos tekisin harjoituksen uudelleen, poistaisin .pug-tiedoston kokonaan välttääkseni sen aiheuttamat ongelmat ja keskittyisin pelkästään index.html-tiedoston muokkaamiseen. </p> <p>Linkki harjoitukseen GitHubissa:</p> <a href="https://github.com/PaulaRii/REST1" >https://github.com/PaulaRii/REST1</a > </div> <div class="flex-shrink-0"> <span class="text-primary">Toukokuu</span> </div> </div> </div> </section> <hr class="m-0" /> <!-- Education--> <section class="resume-section" id="education"> <div class="resume-section-content"> <h2 class="mb-5">Palauteosio</h2> <div class="mb-4"> <strong>Alkutilanne:</strong> <p> Ennen kurssia tietoni ja taitoni web-ohjelmoinnista olivat lähes alkeelliset. </p> </div> <div class="mb-4"> <strong>Nykytilanne:</strong> <p> Koen nyt osaavani käyttää Bootstrappiä, ja luoda ainakin jokseenkin toimivia web-sivuja sekä uskon ymmärtäväni pääperiaatteet REST API:sta ja Reactin käytöstä. Lisäksi hahmotan nyt paremmin tietokantaohjelmointia ja siten miten websivuihin saa tehtyä AJAX:illa asynkronisia kutsuja. Myös tuli palauteltua mieleen Javascriptin sekä Git:in käyttöä. </p> </div> <div class="mb-4"> <strong>Ajankäyttö:</strong> <p> En tajunnut kurssilla ottaa käyttöön Clockifyitä seuraamaan ajankäyttöäni (tähän olisi hyvä muistuttaa opiskelijoita), joten en ole aivan kärryillä siitä kuinka monta tuntia olen kurssin suorittamiseen käyttänyt. Kuitenkin tuntuu, että lähes jokaiseen tehtävään (ensimmäisiä tehtäviä lukuunottamatta) tarvitsin enemmän aikaa kuin ehkä oli tarkoitettu niihin käytettäväksi. Uskon, että käytin lopulta aikaa huomattavasti enemmän kuin mitä oli laskettu kurssin suorittamiseen. </p> </div> <div class="mb-4"> <strong>Tukevat tekijät:</strong> <p> Luennoilla sai mukavasti tukea tehtävien tekemiseen. Oli hyvä, että niiden alkuun saattamiseen käytettiin aikaa luennolla. ChatGPT:n kanssa keskustelu kurssin teemoista on ollut myös erittäin hyvä tuki, niin virheiden löytämiseen koodista kuin myös avaamaan hankalia käsitteitä, joihin ei mielestäni tunnilla käytetty tarpeeksi aikaa, ja joiden opiskelu jätettiinkin enemmän opiskelijan oman aktiivisuuden varaan. Muistan keskustelleeni erityisen paljon REST API:in liittyvistä asioista ChatGPT:n kanssa. Luennoilla tuli aina hirmuisen paljon informaatiota lyhyessä ajassa, ja sitä informaatiotulvaa on ollut hyvä avata tekoälyn kanssa. </p> </div> <div class="mb-4"> <strong>Häiritsevät tekijät:</strong> <p> Mielestäni olisi ollut parempi jakaa luennot kahteen kertaan viikossa. Luennot olivat hyvin raskaita, ja kun koko viikon käsiteltävät asiat ahdetaan yhteen sessioon niin ei siinä oikein pysty sulattelemaan kaikkea kuulemaansa ja tulee sellainen informaatioähky ja tuntuu, ettei tunnilla käsitellyt asiat oikein tahdo jäädä päähän. Positiivista oli se, että oli kaksi viikkoa aikaa sulatella saatua informaatiota ja paneutua harjoitustehtävien tekemiseen. </p> </div> <div class="mb-4"> <strong>Ohjaus ja apu:</strong> <p> Luennoilla sai hyvin ohjausta, siitä kiitos luennoitsijalle. Arvostan sitä, että aina varmistettiin, että ovathan kaikki yhä kelkassa mukana (vaikka lopulta itse putosinkin kelkasta ja kurssin suorittaminen pääsi venymään...). </p> </div> <div class="mb-4"> <strong>Kohokohdat ja toiveet:</strong> <p> Oli hieno fiilis, kun pitkän taistelun jälkeen sai tehtävän toimimaan. Erityisen suuria haasteita oli harjoitus 6:sen kanssa, mutta kun sain sen lopulta valmiiksi, oli aika voittajafiilis. Toiveena olisi, että opitut asiat säilyvät muistissa ja niitä kykenesi jatkossa hyödyntämään. </p> </div> <div class="mb-4"> <strong>Tulevaisuuden suunnitelmat:</strong> <p> Haluan suunnitella omat nettisivut ja sitä varten tulen varmaankin hyödyntämään kurssilla opittuja asioita. Muutoin web-ohjelmointi ei ole ollut itselläni suuren kiinnostuksen kohteena, joskin kuitenkin päädyin työskentelemään GenAI-hankkeessa web-selaimessa toimivan platformer-pelin kanssa, joten jonkun verran näitä asioita on tullut kuitenkin vastaan tässä kevään aikana jo. </p> </div> </div> </section> <hr class="m-0" /> </div> <!-- Bootstrap core JS--> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script> <!-- Core theme JS--> <script src="js/scripts.js"></script> </body> </html> ```