Harjutus 1:

REST API – REST on mittekohustuslikke soovitusi (best practices), kuidas hästikäituvad rakendused võiksid andmeid üle veebi (see tähendab kasutades HTTP protokolli) vahetada ja igal veebiteenuse ehitajal on RESTist oma spetsiifiline nägemus

REST-i (Representational State Transfer) on tavaliselt nimetatud pigem veebiteenuste arhitektuuristiiliks kui protokolliks või standardiks.

Harjutus osa:

1. Paigalda Node.js
2. Loo töölauale kaust rest–api 
3. Käivita koodiredaktor (nt VS Code, WebStorm vms) ja ava see kaust projektina
4. Loo kausta fail index.js järgneva sisuga:

const express = require('express');
const cors = require('cors');
const app = express();
 
app.use(cors());        // Avoid CORS errors in browsers
app.use(express.json()) // Populate req.body
 
const widgets = [
    { id: 1, name: "Cizzbor", price: 29.99 },
    { id: 2, name: "Woowo", price: 26.99 },
    { id: 3, name: "Crazlinger", price: 59.99 },
]
 
app.get('/widgets', (req, res) => {
    res.send(widgets)
})
 
app.get('/widgets/:id', (req, res) => {
    if (typeof widgets[req.params.id - 1] === 'undefined') {
        return res.status(404).send({ error: "Widget not found" })
    }
    res.send(widgets[req.params.id - 1])
})
 
app.post('/widgets', (req, res) => {
    if (!req.body.name || !req.body.price) {
        return res.status(400).send({ error: 'One or all params are missing' })
    }
    let newWidget = {
        id: widgets.length + 1,
        price: req.body.price,
        name: req.body.name
    }
    widgets.push(newWidget)
    res.status(201).location('localhost:8080/widgets/' + (widgets.length - 1)).send(
        newWidget
    )
})
 
app.listen(8080, () => {
    console.log(`API up at: http://localhost:8080`)
})

5. Käivita koodiredaktoris terminal ja seal järgnevad käsud:

1. npm init -y // package.json initsialiseerib node projekti
2. npm i express cors // kausta node_moodules installib express ja  cors paketti
3. node .  //käivitab index.js faili

npm init -y
npm i express cors
node .

6. Tee terminalis xh’ga GET päring vastu API-t:

xh -v localhost:8080/widgets

7.  Tee terminalis xh’ga GET päring vastu API-t, mis tagastab kõik vidinad

xh -v localhost:8080/widgets/1

8. Tee terminalis xh’ga POST päring vastu API-t, mis lisab uue vidina:

xh -v localhost:8080/widgets name=Fozzockle price=39.99

9. Tee terminalis xh’ga POST päring vastu API-t, mis kustutab ühe vidina:

xh -v DELETE localhost:8080/widgets/2

Harjutus 2: Loo Codesandbox-is HTML leht, mis kuvab auto andmeid

Kasutades juhiseid lisasin vajalikud andmed ja tegin selle kuvamiseks, kõik see tegin Sandboxi saidil

Kopeerisin ülesande koodi ja lisasin seejärel vajalikud read ja andmed.

import "./styles.css";

const myjson = [
  {
    "Car 0": {
      Color: "Rose Red",
      "Tinted Windows": false,
      Wheels: 4,
      "Roof Cargo": null,
      Audiosystem: "FM Radio, MP3, MP4 and MKV player, harman/kardon speakers",
      Accessories: "satnav, cruise control",
    },
    Car1: {
      Color: "Navy blue",
      "Tinted Windows": true,
      Wheels: 4,
      "Roof Cargo": "Thule",
      Audiosystem:
        "FM Radio, Apple CarPlay/Android Auto, Bowers & Wilkins Premium Sound speakers",
      Accessories: "self drive system, luggage cover",
    },
  },
];

document.getElementById("app").innerHTML = `
<div id="json">
    <h1> Car Properties </h1>
    <h2> Car 0 </h2>
    <p>Color: ${myjson[0]["Car 0"].Color}</p>
    <p>Tinted Windows: ${myjson[0]["Car 0"]["Tinted Windows"]}</p>
    <p>Wheels: ${myjson[0]["Car 0"].Wheels}</p>
    <p>Roof Cargo: ${myjson[0]["Car 0"]["Roof Carho"]}</p>
    <p>Audiosystem: ${myjson[0]["Car 0"].Audiosystem}</p>
    <p>Accessories: ${myjson[0]["Car 0"].Accessories}</p>
    <h2> Car1 </h2>
    <p>Color: ${myjson[0].Car1.Color}</p>
    <p>Tinted Windows: ${myjson[0].Car1["Tinted Windows"]}</p>
    <p>Wheels: ${myjson[0].Car1.Wheels}</p>
    <p>Roof Cargo: ${myjson[0].Car1["Roof Carho"]}</p>
    <p>Audiosystem: ${myjson[0].Car1.Audiosystem}</p>
    <p>Accessories: ${myjson[0].Car1.Accessories}</p>
</div>
`;

Võtsin jooned ja andmed allolevalt pildilt:

Lõppkokkuvõttes näeb see välja nii:

Harjutus 3: sessionStorage

Ava konsool ning kirjuta konsoolile sessionStorage ning vajuta ENTER. Näed, et Session Storage on tühi.

Tee uus käsk sessionStorage.setItem('color','orange'). Selle käsuga lisati Session Storage’isse uued andmed.

Kirjuta uus käsk sessionStorage.getItem('color') ning näed, et väljastatakse sessionStorage’ist sinu lemmikvärv.

Et näha, mis on Session Storage’isse salvestatud, mine Application>Session Storage>vastav domeen

Harjutus 4: localStorage

Mine sellele vahekaardile tagasi, kus viimati sessionStorage käske sooritasid.

Ava uuesti konsool ning kirjuta localStorage. Näed, et see on tühi.

Tee uus käsk localStorage.setItem('car','skoda'). Selle käsuga lisati Local Storage’isse uued andmed.

Soorita käsk localStorage.getItem(car) ning näed, et localStoragesse väljastatakse sinu lemmikauto.

Nüüd tee uuesti uus vaheaken ning vaata Application>Local Storage alla. Näed, et see on sinna salvestatud.

Harjutus 5: Küpsised

xh on HTTP-klient, millel on sõbralik käsurea liides. See püüab saada loetavat väljundit ja hõlpsasti kasutatavaid valikuid. xh ühildub enamasti HTTPie-ga: vt http(1). Suvandit –curl saab päringu saatmise asemel kasutada käsu curl(1) tõlke printimiseks.

Harjutus 6: Peekon API

Ava veebilehitsejas Code Sandbox sait

Vali Official Templates alt static

Kirjuta pildil olev kood index.html faili. Alustuseks kasuta HTML trafaretti (hüüumärk ja tab klahv).

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Styled Template</title>
  </head>
  <body>
    <button type="button" onclick="loadDoc()">Request bacon</button>
    <p id="demo"></p>
 
    <script>
      function loadDoc() {
        const xhttp = new XMLHttpRequest();
        xhttp.onload = function () {
          const response = JSON.parse(this.responseText);
          const listContainer = document.getElementById("demo");
          const ul = document.createElement("ul");
          response.forEach(function (item) {
            const li = document.createElement("li");
            li.textContent = item;
            ul.appendChild(li);
          });
          listContainer.innerHTML = "";
          listContainer.appendChild(ul);
        };
        xhttp.open("GET", "https://baconipsum.com/api/?type=all-meat");
        xhttp.send();
      }
    </script>
  </body>
</html>

styles.css:


      body {
        font-family: Arial, sans-serif;
        background-color: #f4f4f4;
        color: #333;
        text-align: center;
        margin-top: 50px;
      }
 
      button {
        background-color: #ff6347;
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        font-size: 16px;
        transition: background-color 0.3s ease;
      }
 
      button:hover {
        background-color: #ff4500;
      }
 
      p {
        margin-top: 20px;
        font-size: 18px;
      }

Sandbox:

https://codesandbox.io/p/sandbox/zwt8c3

Harjutus 7: Github API

Selle ülesande puhul peate looma veebirakenduse, mis kasutab kasutajaprofiili andmete toomiseks GitHubi avalikku API-d.

  • REST (Representational State Transfer) on arhitektuurimudel, mida kasutatakse veebiteenuste loomisel ja rakenduste vahelise suhtluse lihtsustamiseks
  • Github access token – Kasutaja juurdepääsuluba on teatud tüüpi OAuthi luba. Erinevalt traditsioonilisest OAuthi märgist ei kasuta kasutaja juurdepääsuluba ulatust. Selle asemel kasutab see peeneteralisi õigusi.
  • FETCH – on JavaScripti sisseehitatud funktsioon, mis on loodud HTTP-päringute tegemiseks. See võimaldab teil kaugserverist andmeid vastu võtta ja vastuseid töödelda.
import "./styles.css";  // Impordi stiilid välisest failist

// Muutujad profiiliandmete salvestamiseks
let profileName = "";
let profileId = "";
let profileLink = "";
let profileRepos = "";
let profilePicture = "";

// Asünkroonne funktsioon GitHubi profiiliandmete pärimiseks
async function fetchProfile(username) {
  try {
    // Tee päring GitHubi API-le profiiliandmete saamiseks
    const response = await fetch(`https://api.github.com/users/${username}`);
    
    // Muuda vastus JSON formaati
    const data = await response.json();

    // Uuenda muutujaid saadud andmetega
    profileName = data.login;
    profileId = data.id;
    profileLink = data.html_url;
    profileRepos = data.public_repos;
    profilePicture = data.avatar_url;

    // Kuvage uuendatud andmed lehel
    renderPage();
  } catch (error) {
    // Käsitle päringu vigu
    console.error("Viga profiili pärimisel:", error);
  }
}

// Funktsioon lehe sisu kuvamiseks
function renderPage() {
  // Uuenda elemendi sisu, mille id on "app"
  document.getElementById("app").innerHTML = `
    <div>
      <h1>Github profiili vaatamine</h1>
      <p>Palun sisesta profiilinimi: </p>
      <input id="username-input" />  <!-- Sisendväli kasutajanime sisestamiseks -->
      <div class="content">
        <h1 id="name">Nimi: ${profileName}</h1>
        <p id="id">Id: ${profileId}</p>
        <p id="reports">Avalikud repod: ${profileRepos}</p>
        <p id="profile-url">
          Link: <a href="${profileLink}" target="_blank">/users/${profileName}</a>
          <!-- Link kasutaja profiilile -->
        </p>
        <div id="profile-avatar">
          <img src="${profilePicture}" alt="${profileName} profiilifoto laadimine...." 
               style="width: 100px; height: 100px; border-radius: 60%;" />
          <!-- Kasutaja avatar -->
        </div>
      </div>
    </div>
  `;

  // Lisa sündmuste töötleja sisendväljale
  document
    .getElementById("username-input")
    .addEventListener("keyup", function (event) {
      // Kontrolli, kas vajutati Enteri klahvi
      if (event.key === "Enter") {
        // Hangi kasutaja nimi sisendväljalt
        const username = event.target.value;
        // Kutsu välja profiili pärimise funktsioon
        fetchProfile(username);
      }
    });
}

// Esmane lehe kuvamine
renderPage();
body {
  background: linear-gradient(135deg, #000, #1a1a1a), url("clonnex.gif");
  background-size: cover;
  background-blend-mode: overlay;
  color: #e0e0e0;
  font-family: "Roboto", sans-serif;
  margin: 0;
  padding: 20px;
}

h1 {
  color: #ff3399;
  font-size: 36px;
  font-weight: 700;
  text-shadow: 2px 2px 5px rgba(255, 51, 102, 0.6);
  margin-bottom: 15px;
  letter-spacing: 1.5px;
}

p {
  font-size: 20px;
  line-height: 1.8;
  margin: 0;
}

#json {
  background: rgba(28, 28, 28, 0.9);
  border-radius: 12px;
  padding: 25px;
  margin-bottom: 25px;
  box-shadow: 0 6px 12px rgba(255, 0, 102, 0.4);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

#json:hover {
  transform: translateY(-5px);
  box-shadow: 0 8px 16px rgba(255, 0, 102, 0.6);
}

#json:last-child {
  margin-bottom: 0;
}

Harjutus 8: XML Kuvamine Lehel

XML (Extensible Markup Language) on W3C poolt välja töötatud ja soovitatud standardne üldotstarbeline märgistuskeel struktureeritud teabe vahetamiseks infosüsteemide vahel, eriti veebirakendustes Internetis.

XML kuvamine läbi JS

games.xml:

<?xml version="1.0" encoding="UTF-8"?>
<gameslist>
 
<game>
<title lang="en">Hearthstone</title>
<price>Free</price>
<platforms>
    <platform>PC</platform>
    <platform>Mobile</platform>
</platforms>
</game>
 
<game>
<title lang="en">Dota2</title>
<price>Free</price>
<platforms>
    <platform>PC</platform>
</platforms>
</game>
 
<game>
<title lang="en">TESV</title>
<price>30</price>
<platforms>
    <platform>PC</platform>
    <platform>PS4</platform>
    <platform>XBOX</platform>
</platforms>
</game>
 
</gameslist>

index.js:

document.getElementById("app").innerHTML = "<table id='xmlTable'></table>";
let xmlhttp = new XMLHttpRequest(); // Create an XMLHttpRequest object
 
xmlhttp.open("GET", "src/games.xml", false);
xmlhttp.send();
 
let XMLContent = xmlhttp.responseXML;
 
let tableRows =
  "<thead><tr><th>Title</th><th>Price</th><th>Platform</th></tr></thead>";
let gameElements = XMLContent.getElementsByTagName("game");
 
for (let i = 0; i < gameElements.length; i++) {
  tableRows +=
    "<tr><td>" +
    gameElements[i].getElementsByTagName("title")[0].childNodes[0].nodeValue +
    "</td><td>" +
    gameElements[i].getElementsByTagName("price")[0].childNodes[0].nodeValue +
    "</td><td>";
  let platforms = gameElements[i].getElementsByTagName("platform");
  for (let j = 0; j < platforms.length; j++) {
    tableRows += platforms[j].childNodes[0].nodeValue + "/";
  }
  tableRows += "</td></tr>";
}
document.getElementById("xmlTable").innerHTML = tableRows;

styles.css:

#xmlTable {
  border-collapse: collapse;
  width: 100%;
  margin-top: 20px;
}
 
#xmlTable th,
#xmlTable td {
  border: 1px solid gray;
  padding: 8px;
  text-align: left;
}
 
#xmlTable th {
  background-color: gray;
}
 
#xmlTable tr:nth-child(even) {
  background-color: #f9f9f9;
}
 
#xmlTable tr:hover {
  background-color: #ddd;
}
 
#xmlTable th {
  cursor: pointer;
}

Harjutus 10: Saada Email Github Push-l

Kui esitate muudatusi GitHubi repositooriumi, on hea mõte luua informatiivne kommiteerimisteade. Ja see ülesanne võimaldab meil mõista, kuidas saata push-in e-kirju Githubile.

Kopeeritud tühi kaustas loome -> .github , .github kaustas loome -> workflows ja seal loome pildil olev fail, sisuga.

name: Send email on push
 
on:
  push:
    branches:
      - main # Kontrollib, kas push on tehtud 'main' harusse
 
jobs:
  mail_on_push:
    runs-on: ubuntu-latest
    steps:
      - name: Send mail
        # kasutatakse GitHubi tegevust e-kirjade saatmiseks
        uses: dawidd6/action-send-mail@v3
        with:
          # SMTP serveri aadress ja port Gmaili jaoks
          server_address: smtp.gmail.com
          server_port: 465
          # kasutajanimi ja parool, mis on salvestatud GitHubi saladustesse
          username: ${{ secrets.MAIL_USERNAME }}
          password: ${{ secrets.MAIL_PASSWORD }}
          subject: "Push Notification for ${{ github.repository }} on branch ${{ github.ref }}"
          to: "arkadikorotitsh@gmail.com"
          body: |
            Tehti push järgmisele repositooriumile: ${{ github.repository }} harusse: ${{ github.ref }}.
 
            **Detailid:**
            - Commit: ${{ github.sha }}
            - Commiti sõnum: ${{ github.event.head_commit.message }}
            - Commiti autor: ${{ github.event.head_commit.author.name }} ({{ github.event.head_commit.author.email }})
            - Pusher: ${{ github.event.pusher.name }}
            - **Pushi kuupäev ja aeg**: ${{ github.event.head_commit.timestamp }}
 
            Vaata commit'i GitHubis: [Commiti link](${{ github.event.head_commit.url }})
 
          # saatja nimi, mis kuvatakse e-kirjas
          from: Github Actions

saadetud sõnum on kättesaadetud

Harjutus 11: Websocket API

WebSocket API võimaldab kliendil luua kahepoolset („dupleks“) suhtlust serveriga.

server:

client:

index.html

<!doctype html>
<form name="publish">
    <input type="text" name="message" maxlength="50"/>
    <input type="submit" value="Send"/>
</form>

<div id="messages"></div>

<script>
    let url = location.host == 'localhost' ?
        'ws://localhost:8080/ws' : location.host == 'javascript.local' ?
            `ws://javascript.local/article/websocket/chat/ws` : // dev integration with local site
            `wss://javascript.info/article/websocket/chat/ws`; // prod integration with javascript.info
    //loome objekti koos veebisoketiga
    let socket = new WebSocket(url);

    // sõnumi saatmine vormile
    document.forms.publish.onsubmit = function() {
        let outgoingMessage = this.message.value;

        socket.send(outgoingMessage);
        return false;
    };

    // töödelda sissetulevaid sõnumeid
    socket.onmessage = function(event) {
        let incomingMessage = event.data;
        showMessage(incomingMessage);
    };
    //kui kasutaja on socket'i sulgenud, kirjutame sellest konsooli.
    socket.onclose = event => console.log(`Closed ${event.code}`);

    // Näita sõnumeid div#messages
    function showMessage(message) {
        let messageElem = document.createElement('div');
        messageElem.textContent = message;
        document.getElementById('messages').prepend(messageElem);}
</script>

index.js

//Node’i WebSocket’i sisaldamine.
const http = require('http');
const fs = require('fs');
const ws = require('ws');

//Serveri seadistamine
const wss = new ws.Server({ noServer: true });

function accept(req, res) {
    if (req.url === '/ws' && req.headers.upgrade &&
        req.headers.upgrade.toLowerCase() === 'websocket' &&
        req.headers.connection.match(/\bupgrade\b/i)) {
        wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onSocketConnect);
    } else if (req.url === '/') {
        // Отправляем index.html
        fs.createReadStream('./index.html').pipe(res);
    } else {
        // Страница не найдена
        res.writeHead(404);
        res.end();
    }
}
//Ühenduse loomine
const clients = new Set();

function onSocketConnect(ws) {
    clients.add(ws);

    ws.on('message', function(message) {
        message = message.slice(0, 50); // максимальная длина сообщения — 50 символов
        for (let client of clients) {
            client.send(message);
        }
    });

    ws.on('close', function() {
        log('connection closed');
        clients.delete(ws);
    });
}
//Teksti kuvamine
let log;

if (!module["parent"]) {
    log = console.log;
    http.createServer(accept).listen(8080);
} else {
    log = function() {};
    // log = console.log;
    exports.accept = accept;
}

style.css

body {
    font-family: Arial, sans-serif;
    background-color: #f9f9f9;
    margin: 0;
    padding: 20px;
}

form {
    margin-bottom: 20px;
}

input[type="text"] {
    width: 70%;
    padding: 8px;
    font-size: 14px;
    border: 1px solid #ccc;
    border-radius: 4px;
}

input[type="submit"] {
    padding: 8px 16px;
    font-size: 14px;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

input[type="submit"]:hover {
    background-color: #45a049;
}

#messages {
    margin-top: 20px;
}

#messages div {
    background-color: #e1f5fe;
    padding: 10px;
    margin-bottom: 10px;
    border-radius: 4px;
    box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}

terminal

#lae alla WebSocket
npm install ws

#node js allalaadimine internetist

#Serveri käivitamine
node index.js

Harjutus 12: Kuidas genereerida turvaline räsi?

Räsi (inglise keeles hash) on digitaalne sõrmejälg, mis on matemaatiliselt tuletatud allkirjastatava dokumendi bitijadast.
Räsifunktsioon (ingl. hash function) on matemaatiline funktsioon, mis kujutab väärtusi suuremast (või lõpmatust) hulgast fikseeritud väiksema võimsusega lõplikku hulka.

Lisa sinna järgnev kood:

Ava enda koodiredaktor

Tee uus fail nimega generateHash.js

const bcrypt = require('bcrypt');
const myPassword ='markiz12';
 
console.time('Time to generate salt');
const salt = bcrypt.genSaltSync(10);
console.log('Time to generate salt');
 
console.time('Time to generate hash');
const hashedPassword = bcrypt.hashSync(myPassword, salt);
console.log(myPassword+ ' is your password & this is your password after hashing it: '+ hashedPassword);
console.timeEnd('Time to generate hash');

siis terminalis paigaldame bcrypt käsuga: npm install bcrypt

Seletus:

  • Real 1 laaditakse sisse bcrypt-i, mida kasutatakse paroolide krüpteerimiseks
  • Real 5 loob funktsioon genSaltSync soola, mida kasutame real 10 räsi loomiseks. Funktsiooni sees parameeter rounds  (voorud) tähendab tegelikult kulutegurit. Kulutegur kontrollib, kui palju aega kulub ühe räsi arvutamiseks. Mida suurem on kulufaktor, seda rohkem on räsi voorusid. Vaikimisi on voorude arv 10, mis võtab kuskil 0,5 – 1 sekundit aega. Voorude arv 20 võib aga võtta juba ligi terve minuti aega.
  • Real 10 loob funktsioon hashSync räsi, koos soolaga (mille genereerisime real 5).

console.time ja console.timeEnd abil mõõdame funktsioonide aega. console.time ja console.timeEnd on paaris ning neil peab olema sama sisu (label), et leida üles paariline, kus algab või lõpeb aja mõõtmine.