# Wykład 2.
---
## Uruchomienie kodu Javascript w vscode:
potrzebujemy utworzyć plik launch.json. Zawiera on informacje jak uruchomic program.
## 1. Przydatne komendy
`npm init -y` - inicjacja pliku package.json, w którym znajdują się informacje o używanych modułach.
`npm install (moduł)` - zainstaluje w bieżącym projekcie pakiet (moduł)
`npm install (moduł) --save` - zainstaluje moduł lokalnie oraz dodatkowo dopisze zależność do package.json
`npm install (moduł) --g` - zainstaluje modułu globalnie
`npm install` - odtwarza wszystkie zależności zgodnie z opisem w package.json
**Node Package Manager (npm)** - narzędzie npm służy do instalacji i aktualizacji pakietów z globalnego repozytorium. Repozytorium npm jest największym repozytorium pakietów kodu.
**${file}** - informacja w pliku launch.json o tym, że kompilujemy obecnie wyświetlany plik.
---
## 2. Język JavaScript
JavasSript zalicza się do języków luźnotypowanych.
### 2.1 Deklarowanie zmiennych w JS
```javascript=
var a = 12; // oznacza zmienną, ma zasięg funkcyjny, obecnie zastąpione przez poniższe:
let b = 23; // oznacza zmienną, ma zasięg blokowy
const c = 34; // oznacza stałą, ma zasięg blokowy
```
### 2.2 Typy w JavaScript:
**Typy proste (prymitywne)** – proste typy danych, wartości, nie można do nich dodawać składowych, są reprezentowane w pamięci jako tablice bajtów
W JavaScript mamy następujące typy proste:
* `null`
* `undefined`
* `boolean`
* `string`
* `number` w reprezentacji `IEEE 754`, obiekt Math (każda liczba jest 64-bitową liczbą zmiennoprzecinkową)
```javascript=
var num = 20; // prosta liczba
var text = "To jest tekst"; // prosty łańcuch znaków
var p = true; // logiczny - prawda/fałsz
var n = null; // nic
var x; // zmienna z nieokreśloną wartością
```
**Typy złożone (referencyjne)** - obiekty, są reprezentowane jako „referencje” do pamięci zawierającej stany obiektów
```javascript=
var a = { };
a.foo = 123; // dodawanie składowych do obiektu
a['foo'] = 234; // to jest prawie równoważne, ale pozwala np. definiować klucze zawierające spację
a['fo o'] = 345;
```
Każdy obiekt ma zdefiniowane funkcje `ToString()` oraz `valueOf()`, które można przeciążyć.
`Object.keys(obiekt)` wypisuje klucze obiektu
### 2.3 Typy opakowujące
```javascript=
var a = 1;
a.foo = 'foo';
console.log( a.foo ); // wypisze undefined, bo a jest typu prostego
var b = Number(1); // równoważne z powyższym
b.foo = 'foo';
console.log( b.foo ); // wypisze undefined, bo a jest typu prostego
var c = new Number(1);
c.foo = 'foo';
console.log( c.foo ); // wypisze 'foo', bo tworzymy obiekt reprezentujący wartość 1
```
### 2.4 Konwersja (koercja) typów w JS
**Typy konwertowane do false**:
0, -0, NaN, "", false
**Operatory logiczne:**
* `!` -> not
* `||` -> or (jest leniwy tzn na poczatku jest wyliczana wartosc pierwszego wyrazenia i dopiero gdy okaze sie ono false to przechodzimy do drugiego wyrazenia)
* `&&` -> and
**Przykładowe konwersje:**
```javascript=
var p = {};
console.log( p ); // Object
console.log( !p ); // false
console.log( !p+[] ); // 'false'
console.log( [] ); // []
console.log( +[] ); // 0
console.log( (!p+[])[+[]] ); // 'f'
```
### 2.5 typeof, instanceOf
```javascript=
var a = 1;
console.log( typeof a ); // zwraca napis reprezentujący typ
if ( a instanceof Number ) { // sprawdza czy coś jest instancją obiektu
console.log( 'Number' );
}
```
### 2.6 Operatory porównania
* `==` -> "luźne" porównanie, sprawdza czy wartości są takie same, ale po dokonaniu konwersji typów
* `===` -> "dokładne porównanie", sprawdza czy wartości są dokładnie takie same
### 2.7 Napisy
* "" ograniczniki zwykłego napisu
* `` ograniczniki szablonu (*${zmienna}*)
**Przydatne metody**
* `toLowerCase()` Metoda ta konwertuje cały ciąg znaków na małe litery.
* `toUpperCase()` Metoda ta konwertuje cały ciąg znaków na duże litery.
* `replace(oldChar, newChar)` Zamienia wszystkie wystąpienia określonego znaku (oldChar) na nowy znak (newChar).
* `trim()` Usuwa wszystkie spacje z początku i końca ciągu znaków.
* `indexOf(substring)` Zwraca indeks pierwszego wystąpienia określonego podciągu znaków (substring) w ciągu. Jeśli nie znajdzie, zwraca -1.
* `startsWith(prefix)` Sprawdza, czy ciąg znaków zaczyna się od określonego prefiksu (prefix). Zwraca true, jeśli tak, w przeciwnym razie false.
* `endsWith(suffix)` Sprawdza, czy ciąg znaków kończy się określonym sufiksem (suffix). Zwraca true, jeśli tak, w przeciwnym razie false.
### 2.8 Getter/Setter
JavaScript posiada lukier syntaktyczny do definiowania właściwości obiektu, wymagający określenia akcesorów `get` i `set`.
```javascript=
var foo = {
num : 0,
get bar() {
return foo.num;
},
set bar(i) {
foo.num = i;
}
}
console.log( foo.bar ); // wypisze 0
foo.bar = 5;
console.log( foo.bar ); // wypisze 5
```
Możliwe jest ogólniejsze podejście, użycie `Object.defineProperty` za pomocą którego można dodać do obiektu dowolną wartość (pole, właściwość, funkcję)
```javascript=
var foo = { }
Object.defineProperty(foo, 'qux', {
get: function () {
return 18;
}
});
Object.defineProperty(foo, 'baz', {
value: function () {
return 34;
}
});
console.log(foo.qux); // wypisze 18
console.log(foo.baz()); // wypisze 34
```
### 2.9 Tablice
* `slice(start, end)` Wybiera fragment listy na podstawie podanych indeksów.
* `splice(index, k, item1, ...)` Modyfikuje tablicę poprzez usuwanie (k) i/lub dodawanie elementów (item1, ...) od danego indeksu (index).
* `filter(function)` Filtruje elementy tablicy na podstawie zdefiniowanego warunku (function).
* `map(function)` Wykonuje określoną funkcję (function) dla każdego elementu tablicy i zwraca nową listę zawierającą wyniki.
### 2.10 JSON
```javascript=
var p = {
a : 1,
b : {
c : 2
}
}
console.log(p) // zwroci {a :1, b : {...}}
var s = JSON.stringify(p)
console.log(p) // zwroci {"a":1, "b":{ "c":2}}
console.log(s) //
```
### 2.11 Nawiasowanie
```javascript=
function a() {
}
// tak dobrze
function a()
{
}
// tak nie robimy bo domyslnie w javascript sa wstawiane sredniki na koncu linii moze to prowadzic do komplikacji
```


### Lista 2
**Zadanie 2**
```javascript=
// 1. Użycie argumentów innego typu niż string dla operatora [] dostępu do składowej obiektu.
// Co się dzieje jeśli argumentem operatora jest liczba?
const person = {
1: "Jakub",
2: 20
};
console.log(person[1]); // wypisze "Jakub"
// 2. Użycie argumentów innego typu niż number dla operatora [] dostępu do tablicy.
// Co się dzieje jeśli argumentem operatora jest inny obiekt?
const k = {
prop: "1"
};
console.log(person[k.prop]); // Wypisze "Jakub"
// Co się dzieje jeśli argumentem operatora jest napis?
const fruits = ["apple", "orange", "banana"];
console.log(fruits["1"]); //Wypisze "orange"
// Co się dzieje jeśli argumentem operatora jest inny obiekt dla tablic?
const key2 = {
prop: "1"
};
console.log(fruits[key2.prop]); // wypisze "orange"
// Czy i jak zmienia się zawartość tablicy jeśli zostanie do niej dopisana właściwość pod kluczem, który nie jest liczbą?
fruits["2"] = "strawberry"; // wstawi "strawberry" na miejscu o indeksie 2
// Czy można ustawiać wartość atrybutu length tablicy na inną wartość niż liczba elementów w tej tablicy?
fruits.length = 10;
console.log(fruits.length) // wypisze 10
fruits.length = 2;
console.log(fruits.length) // wypisze 2
```
# Wykład 3.
## 1. Funkcje
### 1.1 Zmienna ilość argumentów
Operator rozrzucania, czyli trzykropek: `...` pozwala na użycie dowolnej ilości argumentów w funkcji.
```javascript=
function(...args) {
for (let i = 0; i < args.length; i++) {
console.log(args[i])
}
}
```
### 1.2 Funkcje anonimowe
```javascript=
function(x) {
x > 2
}
(x) => {
x > 2
}
```
### 1.3 Funkcja w funkcji
Aby wywołać funkcję w funkcji należy podać jej argumenty w drugim nawiasie.
```javascript=
function create() {
return function () {
return 1;
}
}
console.log(create()) // wypisze [Function (anonymous)]
console.log(create()()); // wypisze 1
```
### 1.4 Domknięcie funkcji
**Domnknięcie funkcji** to dodatkowy obiekt wiążący funkcję ze środowiskiem.
```javascript=
function sumpartial(x) {
return (y) => {
return x + y;
}
}
var sum1 = sumpartial(1);
console.log(sum1(2));
console.log(sumpartial(1)(2))
```
Nieskończona ilość aplikowalnych argumentów:
```javascript=
function sumpartial(x) {
var acc = x; // nasz akumulator "zapamiętujący" obecną sumę
var func = (y) => {
acc += y;
return func;
}
func.valueOf = () => {
return acc;
}
return func;
}
console.log(+sumpartial(4)(5)(6));
```
### 1.5 Memoizacja
Przydaje się zwłaszcza w przypadku, gdy funkcja w argumencie jest rekurencyjna (np. ciąg Fibonacciego)
```javascript=
function memo(func){
var cache = {}
return function(n){
if (n in cache){
return cache[n];
}
else{
var result = func(n);
cache[n] = result;
return result;
}
}
}
```
### 1.6 IIFE
Funkcja jest wywołana zaraz po zdefiniowaniu.
Let to lukier syntaktyczny dla IIFE, obie poniższe definicje są sobie równoważne i zmienna k ma zasięg blokowy.
```javascript=
{
(function() {
var k;
}())
let k
}
```
### 1.7 Currying
Currying to inaczej rozwijanie funkcji, w którym częściowa aplikacja jest możliwa dla każdego argumentu z osobna (wywołanie z n argumentami zamienia się na n wywołań z jednym argumentem).
```javascript=
function sum3(x, y, z) {
return x + y + z;
}
function curry(fn) {
function rec(fn, i, args) {
if (i < fn.length) {
return (x) => {
args.push(x);
return rec(fn, i + 1, args);
}
}
else {
return fn(...args);
}
}
return rec(fn, 0, []);
}
var currysum3 = curry(sum3);
console.log(currysum3(1)(2)(3));
```
### 1.8 this, call, bind, apply
* **this**
W funkcji wywołanej z wiązaniem na obiekcie(`o.funkcja()`), `this` ma wartość referencji do tego obiektu.
```javascript=
var person = {
name: 'jan',
say: function () {
return this.name;
}
}
console.log(person.say());
```
Alternatywnie:
```javascript=
var person = {
name: 'jan',
say: say // lub po prostu say
}
function say() {
return this.name
}
console.log(person.say());
```
* **call**
Służy do wywołania funkcji, gdzie argumentem jest obiekt, w którego kontekście ma być wywołana. Argumentami `call` jest to, co ma być widoczne jako `this`, wewnątrz funkcji.
```javascript=
var person = {
name: 'jan',
}
function say() {
return this.name
}
console.log(say.call(person));
```
* **apply**
Działa bardzo podobnie do `call`, z tą różnicą że argumenty są przekazywane jako lista, nie po przecinku jak w `call`.
Poniższe zapisy są sobie równoważne:
```javascript=
function f(a, b, c){
return this, a, b, c
}
var o = {
x: 1
}
f.apply(o, [1, 2, 3])
f.call(o, 1, 2, 3)
```
* **bind**
Bind zaaplikowany do funkcji, zwraca inną funkcję, w której `this` już jest zawsze zamieniony na jakiś obiekt.
```javascript=
function foo(y, z) {
return this.x + y + z;
}
var o = {
x: 1
}
var baz = foo.bind(o);
console.log(baz(1, 2)); // wypisze 4
```
## 2. Iteratory, generatory
### 2.1 Iterator
**Iterator** to funkcja bezargumentowa która zwraca obiekt, który ma jedno pole, `next`, które jest funkcją zwracającą obiekt o polach `value` i `done`.
```javascript=
function createIterator() {
var acc = 0;
return {
next: function () {
return {
value: acc,
done: acc++ >= 10
}
}
}
}
var it = createIterator();
for (var result; result = it.next(), !result.done;) {
console.log(result.value);
}
```
Funkcja iteratora jeśli zostanie użyta w obiekcie jako wartość składowej `Symbol.iterator`, obiekt uzyskuje możliwość iterowania jego zawartości za pomocą for-of.
```javascript=
var foo = {
[Symbol.iterator]: createIterator
}
for (var f of foo) {
console.log(f);
}
```
W obu przypadkach zostaną wypisane liczby od 0 do 9.
### 2.2 Generator
**Generator** to skrócony sposób zapisu kodu iteratora, dodający zwracanie bieżącej wartości za pomocą `yield`. Iterowanie generatora działa tak samo jak iteratora.
```javascript=
function* createGenerator() {
for (var i = 0; i < 10; i++) {
yield i;
}
}
```
Gwiazdka przy `function` jest niezbędna. Pętla for, oraz for-of działają tak samo jak w iteratorze.
### 2.3 Próba oszustwa
Iterator/Generator powinien być funkcją bezargumentową, ale jednak chcemy przekazać mu jakieś wartości. Można po prostu zwrócić funkcję bezargumentową.
```javascript=
function createGenerator(n) {
return function* () {
for (var i = 0; i < n; i++) {
yield i;
}
}
}
var foo = {
[Symbol.iterator]: createGenerator(10)
}
for (var val of foo) {
console.log(val); // wypisze liczby od 0 do 9
}
```
### Lista 3
**Zadanie 2**
```javascript=
function forEach(a, f){
if (a[0] === undefined){
return [undefined];
}
else{
f(a[0]);
forEach(a.slice(1), f);
}
}
function map(a, f){
if (a.length == 0){
return [];
}
else{
return [(f(a[0])), ...map(a.slice(1), f)];
}
}
function filter(a, f){
if (a.length == 0){
return [];
}
else if (f(a[0])){
return [a[0], ...filter(a.slice(1), f)]
}
else{
return [...filter(a.slice(1), f)]
}
}
```
---
# Wykład 4.
## 1. Paradygmat obiektowy
**Projektowanie obiektowe** - określanie odpowiedzialności obiektów (klas) i ich relacji względem siebie. Wszystkie dobre praktyki, zasady, wzorce sprowadzają się do tego jak właściwie rozdzielić odpowiedzialność na zbiór obiektów (klas).
W JavaScript jeżeli dwa niepowiązane ze sobą w żaden sposób obiekty mają „podobny wygląd” (pola/metody), to obu można użyć w tym samym kontekście i do tego nie jest potrzebna żadna kontrola typów:
```javascript=
var person = {
name: 'jan',
say: function () {
return this.name;
}
}
var car = {
brand: 'skoda',
say: function () {
return this.brand;
}
}
function describe(item) {
console.log(item.say());
}
describe(person);
describe(car);
```
Jest to tzw. **Duck Typing**, czyli rozpoznawanie typu obiektu poprzez pola, które zawiera.
*„If it walks like a duck and it quacks like a duck, then it must be a duck.”*
W Javascript są trzy równoważne modele implementowania struktur obiektów:
* `{}`
* `new`
* `Object.create()`
W językach takich jak C# czy Java jest tylko jeden sposób tworzenia nowych instancji obiektów – to operator `new`
## 2. Obiektowość z { }, bez dziedziczenia
Pierwsza technika obiektowości w JS to 'udawanie' konstruktorów, poprzez proste funkcje tworzące obiekty. Wadą jest jednak niepotrzebne zużycie pamięci na kopiowanie metod.
```javascript=
function Person(name, surname) {
return {
name: name,
surname: surname,
say: function () {
return `${this.name} ${this.surname}`;
}
}
}
var p = Person('jan', 'kowalski');
console.log(p.say());
```
## 3. Obiektowość prototypowa
Obiektowość prototypowa zestawia wiele instancji obiektów w łańcuchy, w których każdy obiekt wskazuje na swój prototyp.
### 3.1 Prototyp
Prototyp to taki "poprzednik" istniejącego obiektu.
Nadrzędnym prototypem każdego obiektu jest `Object.prototype`, z którego każdy inny obiekt dziedziczy metody np. `toString()` albo `valueOf()`.
* Aby zmienić prototyp używamy funkcji: `Object.setPrototypeOf(obiekt, nowyPrototyp)`
* Aby odczytać prototyp istniejącego obiektu używamy funkcji: `Object.setPrototypeOf(obiekt)`
```javascript=
var o = {
foo: null
}
var proto = {
foo: 1,
bar: 2
}
Object.setPrototypeOf(o, proto);
console.log(o.foo); // wypisze null
console.log(o.bar); // bar pochodzi z obiektu proto, wypisze 2
console.log(o.foo); // wypisze null
```
#### Ograniczenia
* Obiekt może mieć pusty prototyp. W szczególności, ten prototyp wszystkich obiektów, czyli `Object.prototype`, ma pusty prototyp. Dzięki temu łańcuch prototypów zawsze się kończy.
* Łańcuch prototypów nie może mieć cykli. Dosyć logiczne.
## 4. Obiektowość z new
W JavaScript obiektowość z użyciem słowa kluczowego `new` odnosi się do tworzenia nowych instancji obiektów przy użyciu konstruktorów.
```javascript=
function Person(name, age) {
this.name = name;
this.age = age;
}
// dodawanie nowych metod, prototyp wszystkich nowych instancji obiektu:
Person.prototype.say = function () {
return this.name;
};
var person = new Person("Jan", 21);
console.log(person.age);
```
Wewnątrz konstruktora `this` odnosi się do nowo tworzonej instancji obiektu.
Możemy też łatwo modyfikować pola nowych instancji:
```javascript=
person.age = 22
console.log(person.age); // wypisze 22
```
#### Dziedziczenie
Możemy w łatwy sposób osiągnąć coś na wzór dziedziczenia:
```javascript=
var Worker = function (name, surname, age) {
Person.call(this, name, age);
this.surname = surname;
}
// ustawienie prototypu dla worker
Worker.prototype = Object.create(Person.prototype);
var worker = new Worker('jan', 'kowalski', 48);
console.log(worker.say());
```
Dodanie nowej funkcjonalności (pola lub funkcji) do prototypu automatycznie dodaje ją do wszystkich obiektów o tym prototypie.
#### Przykładowe prototypy:
```javascript=
var o = {}
console.log( Object.getPrototypeOf(o) === Object.prototype ); // true
function foo() {}
console.log( Object.getPrototypeOf(foo) === Function.prototype ); // true
var s = 'ala ma kota';
console.log( Object.getPrototypeOf(s) === String.prototype ); // true
```
## 5. Obiektowość z Object.create()
Funkcja `Object.create()` tworzy nową instancję obiektu i ustawia jej wskazany obiekt jako prototyp.
Konstruktor - musi być rozdzielony na tworzenie przez `Object.create` (poprawne zestawienie łańcucha prototypów) i metodę `init` która jedynie inicuje stan obiektu.
```javascript=
var Person = {
init: function (name, surname) {
this.name = name;
this.surname = surname;
},
say: function () {
return this.name;
}
}
var Worker = Object.create(Person);
Worker.init = function (name, surname, age) {
person.init.call(this, name, surname);
this.age = age;
}
var w = Object.create(Worker);
w.init('tomasz', 'malinowski', 48);
console.log(w.say());
```
Oba sposoby implementacji obiektowości, ten w którym `Object.create()` jest pierwotne i ten w którym `new` jest pierwotne, są równoważne.
## 6. Lukier syntaktyczny definicji klas
```javascript=
class Person {
constructor(name, surname) {
this.name = name;
this.surname = surname;
}
say() {
return this.name + this.surname;
}
}
class Worker extends Person {
constructor(name, surname, age) {
super(name, surname);
this.age = age;
}
say() {
var prev = super.say();
return prev + this.age;
}
}
var w = new Worker('tomasz', 'malinowski', 48);
console.log(w.say());
```
## Lista 4
**Zadanie 2**
Jak odróżnić składową, która pochodzi z obiektu od takiej która pochodzi z prototypu?
```javascript=
var person = {
name: 'jan'
}
var personProto = {
surname: 'kowalski',
age: 30
}
Object.setPrototypeOf(person, personProto);
// zwraca true, jeżeli obiekt zawiera takie pole
function isInObject(obj, propertyName) {
return obj.hasOwnProperty(propertyName);
}
// Wypisuje pola, również te z łańcucha prototypów
for (key in person) {
console.log(key);
}
```
**Zadanie 3**
```javascript=
var Person = function(name) {
this.name = name;
}
var Worker = function(name, age) {
Person.call(this, name);
this.age = age
}
```
* Poprawne podejście
```javascript=
Worker.prototype = Object.create(Person.prototype);
```
Poprawna wersja z wykładu izoluje prototyp, zmiany w dziedziczącym prototypie nie wpłyną na prototyp rodzica.
* Błędne podejście 1:
```javascript=
Worker.prototype = Person.prototype;
```
Modyfikując `Worker.prototype`, poprzez dodanie pola/metody dodajemy je zarówno do Worker.prototype jak i do Person.prototype.
* Błędne podejście 2:
```javascript=
Worker.prototype = new Person();
```
Tworzymy nowy obiekt person wywołujemy jego konstruktor. Nie przekażemy argumentów konstruktora odpowiednich dla `Worker`.
**Zadanie 4**
Nie można dodawać prototypów do typów prostych. Prototypem typów prostych jest `object`.
**Zadanie 5**
Efekt składowych prywatnych.
```javascript=
function Foo() {
this.Bar = function() {
Qux();
}
function Qux(){ // brak dostępu
console.log("qux")
}
this.getName = function() {
return _name;
}
var _name = name; // brak dostępu
}
```
---
# Wykład 5.
## 1. Klasy
### 1.1 Przestrzenie nazw
Inne języki: `namespace`
JavaScript: obiekty zagnieżdżone w obiektach:
```javascript=
UWr = {}
UWr.weppo = {};
UWr.weppo.Person = function(name) {
this.name = name;
}
var p = new UWr.weppo.Person('jan');
console.log(p.name);
```
### 1.2 Moduły
```javascript=
// module.js
module.exports = { module_function };
```
```javascript=
// main.js
let var = require('./module');
var.module_function(5);
```
### 1.3 Dokumentacja
**JSDoc** - standard dokumentacji kodu, pozwala edytorom na wyświetlanie komentarzy, po najechaniu na funkcję napisaną przez nas. Pojawia się przed opisywaną funkcją.
```javascript=
/**
* Funkcja dodająca dwie liczby.
* @param {number} a - Pierwsza liczba.
* @param {number} b - Druga liczba.
* @returns {number} Suma dwóch liczb.
*/
function sum(a, b) {
return a + b;
}
```
## 2. Programowanie asynchroniczne :(
Programowanie asynchroniczne w języku JavaScript polega na wykonywaniu operacji, które mogą trwać różną ilość czasu, bez blokowania wykonywania kolejnych instrukcji.
Główne cechy programowania asynchronicznego w JavaScript to:
* **Funkcje zwrotne (Callbacks)**
Polega to na przekazywaniu funkcji do innych funkcji, które zostaną wykonane, gdy operacja asynchroniczna zakończy się.
* **Obietnice (Promises)**
Obietnice to obiekty reprezentujące wartość, która może być dostępna natychmiast lub w przyszłości.
* **Funkcje async/await**
Funkcje oznaczone jako async zwracają obietnice, a słowo kluczowe await używane jest do oczekiwania na zakończenie operacji asynchronicznej wewnątrz funkcji async.
Podejście async-await jest równoważne callbackom.
### 2.1 Callback Hell
Kolejne wywołania funkcji asynchronicznych w jednym potoku powodują konieczność charakterystycznego zagnieżdżania funkcji zwrotnych, nazwanego **Callback Hell**. Nieumiejętność radzenia sobie z tą niedogodnością struktury kodu jest jednym z powodów dla których Javascript miał przez lata tak niedobrą opinię.
```javascript=
funkcja1(function(response1) {
funkcja2(response1, function(response2) {
funkcja3(response2, function(response3) {
// i tak dalej...
});
});
});
```
### 2.2 Promise
Alternatywą dla funkcji zwrotnych jest wzorzec struktury kodu oparty na obiektach Promise.
Promise jest obiektem który ma:
* **Stan** (Pending, Fulfilled, Rejected)
* **Funkcję do zmiany stanu**
* **Listę tzw. kontynuacji** czyli funkcji, które trzeba wykonać wtedy kiedy wynik będzie dostępny `then()` lub zostanie wyrzucony wyjątek `catch()`
Konytnuacja z kolei zawsze zwraca `Promise`, nawet jeśli technicznie nic nie zwraca. Dzięki temu możliwe jest łańcuchowanie wywołań.
```javascript=
var promise = new Promise((resolve, reject) => {
resolve(17); // zmiana stanu
});
promise
.then(result => {
console.log(result);
})
.then(result => {
console.log(result + 1);
})
.catch(error => {
console.error(error);
});
```
### 2.3 async/await
Lukier syntaktyczny, który umożliwia pisanie asynchronicznego kodu w sposób, który wygląda jak synchroniczny, co znacznie ułatwia zarządzanie asynchronicznością i czytelność kodu.
* **async**:
Funkcje oznaczone jako `async` zwracają obietnice (Promise). Wewnątrz funkcji `async` możemy korzystać z słowa kluczowego `await`, które czeka na zakończenie operacji asynchronicznej i zwraca jej rezultat.
* **await**:
Słowo kluczowe `await` może być używane wewnątrz funkcji oznaczonej jako `async` do oczekiwania na zakończenie operacji asynchronicznej. Działanie funkcji `await` polega na "zawieszeniu" wykonywania funkcji do momentu rozwiązania obietnicy.
```javascript=
function pobierzDane() {
return new Promise(function(resolve) {
setTimeout(function() {
resolve("Dane zostały pobrane!");
}, 2000);
});
}
(async function dzialanie() {
try {
var wynik = await pobierzDane();
console.log(wynik); // "Dane zostały pobrane!"
}
catch (error) {
console.error(error);
}
})();
```
## Lista 5
**Zadanie 1**
Aby zbudować cykl modułów wystarczy na początku pliku dodać `module.exports`.
```javascript=
module.exports = { test2 }
const a = require('./module1.js')
console.log('Module 2 loaded module 1')
function test2(x){
if (x > 0){
console.log(`Module 2: ${x}`)
a.test1(x - 1)
}
}
```
```javascript=
module.exports = { test1 }
const b = require('./module2.js')
console.log('Module 1 loaded module 2')
function test1(x){
if (x > 0){
console.log(`Module 1: ${x}`)
b.test2(x - 1)
}
}
```
**Zadanie 4**
Odczytywanie i wypisywanie zawartości pliku.
```javascript=
var fs = require('fs');
function read() {
return new Promise((resolve, reject) => {
fs.readFile('text.txt', 'utf-8', (err, answer) => {
if (err) {
reject(answer);
}
else{
resolve(answer);
}
})
});
};
(async function main() {
t = await read()
console.log(t)
})()
```
---
# Wykład 6.
## 1. Kilka słów o TypeScript
**TypeScript** to język programowania stworzony przez Microsoft, który rozszerza składnię języka JavaScript poprzez dodanie statycznego typowania. Oznacza to, że TypeScript pozwala programistom określać typy zmiennych, parametrów funkcji i innych elementów kodu, co ułatwia wykrywanie błędów i refaktoryzację kodu.
#### Kilka cech TypeScript:
* **Statyczne typowanie**:
TypeScript umożliwia definiowanie typów zmiennych, parametrów funkcji, wartości zwracanych itp.
* **Kompilacja do JavaScript**:
Kod napisany w TypeScript jest kompilowany do kodu JavaScript, co oznacza, że może być uruchamiany na każdej platformie wspierającej JavaScript. Kod sprawdzany jest w momencie kompilacji.
* **Obsługa klas i interfejsów:**
TypeScript wspiera obiektowość poprzez koncepcje klas i interfejsów.
#### Przydatne komendy:
* `npm install typescript -g` - globalna instalacja TS
* `tsc --init` - inicjalizacja pliku tsconfig.json
* `tsc --watch` - uruchamia kompilator TypeScripta (tsc) w trybie śledzenia. Oznacza to, że kompilator będzie śledził pliki źródłowe TypeScript i automatycznie kompilował je za każdym razem, gdy zostaną zmodyfikowane.
**ts-node** to środowisko uruchomieniowe TypeScript, które rozszerza node o kompilację TS „w locie”. Do tego należy używać polecenia `ts-node plik.ts`.
## 2. System typów

* **unknown** najbardziej ogólny typ, który reprezentuje wartość, o której nie wiadomo, jakiego typu jest w momencie kompilacji. "Bezpieczniejszy" w stosunku do typu`any`.
* **never** można nadać go nadać zmiennej, ale takiej zmiennej nie da się nadać żadnej wartości. Wykorzystuje się go np. w sytuacjach w których funkcja nigdy nie zakończy się, lub jej wartość nigdy nie zostanie zwrócona.
**System typów TS jest znacznie bogatszy niż system typów JS.** Wynika to z tego, że o ile część typów TS i JS pokrywa się (np. zmienna zadeklarowana w TS jako `string` będzie miała w JS też typ `string`) to sporo typów zadeklarowanych w TS po prostu zniknie po kompilacji do JS (np.wszystkie typy zadeklarowane przez programistę z użyciem `type/interface`)
```typescript=
// Typ prosty w TS
let s: string = 's';
console.log(Object.getPrototypeOf(s) === String.prototype); // true
// Typ złożony (strukturalny) w TS
type Person = {
name: string;
surname: string;
}
let p: Person = {
name: 'jan',
surname: 'jan'
}
// po uruchomieniu, na poziomie JS, prototypem p jest Object.prototype
// Person "znika" z pola widzenia systemu typów czasu wykonania
console.log(Object.getPrototypeOf(p) === Object.prototype); //true
```
### 2.1 Inne rodzaje typów
```typescript=
// typ literalny anonimowy: typem zmiennej jest 'x'
let _x1: 'x' = 'x';
// typ literalny został nazwany, X
type X = 'x';
let _x2: X = 'x';
// typ strukturalny anonimowy:
// typem zmiennej jest { name: string, surname: string }
let _person1: { name: string, surname: string } = {
name: 'jan',
surname: 'kowalski'
};
// typ strukturalny został nazwany, Person
type Person = { name: string, surname: string };
let _person2: Person = { name: 'jan', surname: 'kowalski' }
```
#### Type vs Interface
Różnice między `type` a `interface` są nieznaczne i można powiedzieć że to synonimy, z zastrzeżeniem:
* `type` pozwala na tworzenie nowych, bardziej skomplikowanych typów danych, podczas gdy `interface` służy głównie do definiowania kształtu obiektów. Może zawierać tylko deklaracje właściwości i metod, ale nie implementacje.
```typescript=
type Osoba = {
imie: string;
wiek: number;
}
type Adres = {
ulica: string;
kodPocztowy: string;
}
type Klient = Osoba & Adres;
```
```typescript=
interface Osoba {
imie: string;
wiek: number;
}
interface Adres {
ulica: string;
kodPocztowy: string;
}
interface Klient extends Osoba, Adres {
nrTelefonu: string;
}
```
### 2.2 Inferencja typów
**Inferencja typów** to mechanizm, który pozwala na automatyczne wywnioskowanie typów zmiennych na podstawie ich wartości lub kontekstu, bez konieczności jawnego określania typów przez programistę.
```typescript=
type Person = {
name: string,
surname: string
}
function DoWork(p: Person): Person {
// zwraca obiekt literalny - ale struktura jest zgodna!
return {
name: p.name + ' from doWork',
surname: p.surname + " from doWork"
};
}
```
Ani obiekt zwracany z funkcji, ani obiekt przekazywany do funkcji nie ma jawnie zadeklarowanego typu (choć mógłby!) i w obu przypadkach TS jest w stanie zweryfikować poprawność wywołania na podstawie wyłącznie zgodności pól.
typu. **W TypeScript strukturalnie typ** `Person` **oraz typ** `{name: string, surname: string}` **są równoważne!**
### 2.3 Unie i przecięcia typów
* Unia typów `|`
```typescript=
// Unia typów string lub number
let zmienna: string | number;
zmienna = "Hello"; // OK
zmienna = 10; // OK
zmienna = true; // Błąd, wartość typu boolean nie jest częścią unii
```
* Przecięcie typów `&`
```typescript=
// Przecięcie typów Osoba i Adres
interface Osoba {
imie: string;
wiek: number;
}
interface Adres {
ulica: string;
kodPocztowy: string;
}
type Klient = Osoba & Adres;
// Klient będzie zawierać właściwości imie, wiek, ulica i kodPocztowy
```
### 2.4 Strażnik typów
**Strażnik typów** zwraca informacje o przynależności obiektu do jakiegoś typu.
```typescript=
type Person = {
name: string
}
type WorkingPerson = Person & { position: string }
// stażnik typowy (type guard)
function isWorkingPerson(p: Person): p is WorkingPerson {
return 'position' in p;
}
```
### 2.5 Przeciążenie funkcji
TypeScript nie pozwala przeciążyć implementacji funkcji, ale zamiast tego pozwala na przeciążenie samej sygnatury (sposób określania typów parametrów funkcji oraz typu wartości zwracanej przez funkcję).
### 2.6 Jeszcze więcej typów
#### Typy generyczne
```typescript=
function identyfikator<T>(arg: T): T {
return arg;
}
let identyfikatorString: string = identyfikator("hello");
let identyfikatorLiczba: number = identyfikator(42);
```
#### Typy indeksowane
```typescript=
interface Dictionary<T> {
[klucz: string]: T;
}
let slownik: Dictionary<number> = {};
slownik["jeden"] = 1;
slownik["dwa"] = 2;
```
#### Typy funkcyjne
```typescript=
type FunkcjaDodawania = (a: number, b: number) => number;
let dodaj: FunkcjaDodawania = (x, y) => x + y;
let wynik: number = dodaj(3, 5); // wynik: 8
```
### 2.7 keyof, typeof
* `typeof` jest operatorem używanym do uzyskiwania typu wartości, zmiennej lub wyrażenia.
* `keyof` jest operatorem używanym do uzyskiwania typu, który zawiera wszystkie klucze obiektu lub typu.
```typescript=
const liczba = 42;
type TypLiczby = typeof liczba; // TypLiczby zawiera typ "number"
```
```typescript=
type Osoba = {
imie: string;
wiek: number;
email: string;
};
type KluczeOsoby = keyof Osoba; // KluczeOsoby zawiera typ "imie" | "wiek" | "email"
```
### 2.8 Typy mapowane
Jeśli keyof działa tak że z typu strukturalnego wybiera klucze, to czy istnieje operacja odwrotna? Taka, że dla zadanej unii kluczy tworzy typ strukturalny z tymi kluczami? Tak. Do tego służą typy mapowane.
```typescript=
type Osoba = {
imie: string;
wiek: number;
};
type OsobaZDwomaStringami = {
[K in keyof Osoba]: string;
};
// OsobaZDwomaStringami będzie miało typ { imie: string, wiek: string }
```
Typy warunkowe pozwalają na wybór typu na podstawie warunku logicznego.
```typescript=
type AcceptOnly<T> = T extends 'name' ? T : never;
type Name = AcceptOnly<'name'> // 'name'
type NoName = AcceptOnly<'noname'> // never
```
#### Inny ważny przykład
```typescript=
type Person = {
name: string,
surname: string,
age: number,
position: number
}
// pomiń klucze
type ExceptKeys<T, U> = T extends U ? never : T;
// mapuj obiekt na obiekt z pominiętymi kluczami
type OmitKeys<T, K extends keyof T> = { [k in ExceptKeys<keyof T, K>]: T[k] }
// {
// age: number.
// position: number
//}
type WorkingPerson = OmitKeys<Person, 'name' | 'surname'>
```
### 2.9 Kilka wbudowanych typów generycznych
* `Partial<Type>` Konstruuje z zadanego typu typ, który ma wszystkie składowe opcjonalne
* `Required<Type>` Konstruuje z zadanego typu typ, który ma wszystkie składowe wymagane
* `Readonly<Type>` Konstruuje z zadanego typu typ, który ma wszystkie składowe tylko-do-odczytu
* `Record<Keys, Type>` Konstruuje typ z zadanych kluczy i typu wartości
* `Extract<Keys, Keys>` Z zadanej unii typowej zwraca wskazane elementy
* `Exclude<Keys, Keys>` Z zadanej unii typowej wyrzuca wskazane elementy
* `Pick<Type, Keys>` Z zadanego typu struktury zwraca podtyp ze wskazanych kluczy
* `Omit<Type, Keys>` Z zadanego typu struktury zwraca podtyp z wyrzuconymi wskazanymi kluczami
---
# Wykład 7
## 1. HTTP
### 1.1 Protokół
**Protokół HTTP** opracowano na początku lat 90tych. Jest to oparty o TCP/IP protokół komunikacyjny, zaprojektowany do przekazywania treści multimedialnych.
Przez oparty o TCP/IP rozumiemy tu protokół, w warstwie transportowej którego używane są gniazda BSD, czyli standard z początku lat 80tych, zaadoptowany do POSIX jako de facto interoperacyjny standard komunikacyjny. Interfejs gniazd przyjął się w dużej mierze dzięki swojej prostocie konceptualnej, opartej o funkcje:
- **bind**, **listen** i **accept** na serwerze
- **connect** na kliencie
- **send** i **recv** na kliencie i serwerze

### 1.2 Żądanie
Tekst złożony z **wielu linii**, z których **pierwsza** określa **rodzaj żądania i nazwę zasobu**, a **kolejne linie** oznaczają tzw. **nagłówki HTTP**. **Pusta linia oznacza koniec żądania**, chyba że jest to żądanie z parametrami (np. POST czy PUT), wtedy treść żądania może być dowolnie długa. W takim przypadku obowiązkowy jest **nagłówek Content-length**, który określa **długość tej dodatkowej opcjonalnej części**.
### 1.3 Odpowiedź
Tekst lub strumień binarny, interpretowany przez klienta na podstawie opisu w nagłówku **Content-type**, o długości zadanej przez nagłówek **Content-length**
### 1.4 Klienci i debuggery HTTP
Przeglądarka może posiadać **funkcję podglądu sieciowego**, ponieważ podgląd odbywa się w samej przeglądarce, nie ma problemu z podglądem ruchu szyfrowanego (**HTTPs**)
Zewnątrzprocesowy podgląd ruchu między klientem a serwerem możliwy jest albo za pomocą narzędzi niskopoziomowych (np. Wireshark) albo tzw. **debuggerów http** (wykorzystując to, że przeglądarki pozwalają na ustawienie tzw. **proxy** dla ruchu HTTP)
> Przykładowy klient wykorzystujący POST do ścieżki https://httpbin.org/post
```javascript=
var https = require('https');
function promisedRequest() {
return new Promise(function (resolve, reject) {
var qs = new URLSearchParams();
qs.append('foo', 'foo');
qs.append('bar', 'bar');
var postData = qs.toString();
/**
* @type {http.RequestOptions}
*/
var requestParameters = {
host: 'httpbin.org',
port: '443',
path: '/post',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
var client = https.request(requestParameters, function (res) {
var buffer = '';
res
.on('data', function (data) {
buffer += data.toString();
})
.on('end', function () {
resolve(buffer);
});
});
client.write( postData );
client.end();
});
}
(async function() {
var result = await promisedRequest();
console.log( result );
})();
```
### 1.5 Fiddler i Burp
Darmowe debugery http.
Oba narzędzia pozwalają na tworzenie własnych żądań - **kopiowanie i modyfikowanie istniejących** i/lub **tworzenie żądań od** **"zera"**
**Node.js** posiada wsparcie dla tworzenia serwerów HTTP bezpośrednio w bibliotece standardowej, np.
```javascript
var http = require("http");
var server =
http.createServer(
(req, res) => {
//Wymuszenie interpretowania odpowiedzi w określonym kodowaniu
res.setHeader('Content-type', 'text/html; charset=utf-8');
res.end(`hello world ${new Date()}`);
});
server.listen(3000);
console.log('started');
```
Argumentem funkcji tworzącej jest **callback** przyjmujący dwa argumenty:
- **req** typu **IncomingMessage** który jest modelem dla żądania od klienta (stąd można odczytać adres i typ żądania, nagłówki, cookies)
- **res** typu **ServerResponse** który jest modelem dla odpowiedzi dla klienta
Funkcje zwrotne kolejnych żądań (np. wielu użytkowników) trafiają do pętli zdarzeń i tworzą **kolejkę** oczekujących żądań. Są one obsługiwane ***jednowątkowo***.
Asynchroniczność jest kluczowa do zwiększenia przepustowości - procesor przetwarza wyłącznie kod i można zrezygnować z kosztownego oczekiwania na żądanie synchroniczne do zewnętrznego zasobu.
> Na przykład:
> - serwer dostaje żądanie A, ustawia się w kolejce zdarzeń
> - serwer dostaje żądanie B, ustawia się w kolejce zdarzeń
> - serwer rozpoczyna przetwarzanie żądania A, w ramach niego zaczyna odczytywać jakiś plik
> - serwer rozpoczyna przetwarzanie żądania B, w ramach niego zaczyna odczytywać jakiś plik
> - ... serwer czeka w pętli aż zakończy się odczyt plików ...
> - odczyt z żądania A kończy się i do pętli zdarzeń trafia kontynuacja
> - odpowiedź na żądanie A jest przesyłana do klienta
> - odczyt z żądania B kończy się i do pętli zdarzeń trafia kontynuacja
> - odpowiedź na żądanie B jest przesyłana do klienta
>
> W trakcie obsługi obu żądań procesor w żadnym momencie nie czekał na odczyt danych z plików - bo w tym czasie przetwarzał inne żadania z pętli zdarzeń
### 1.6 Klaster
W node.js to grupa procesów, które współdzielą ten sam port TCP. Żądanie trafia do któregoś z procesów dzielących się portem.
## 2. HTTPs
Rozszerzenie protokołu **HTTP** w którym pod żądaniem typu **CONNECT** pojawia się dodatkowy tzw. **handshake** czyli **sekwencja komunikatów zmierzająca do ustalenia klucza szyfrującego komunikację**
Ta część komunikacji wykorzystuje algorytm asymetryczny (RSA), gdzie **serwer** ma **klucz publiczny** (certyfikat) i **klucz prywatny** (nie ujawniony).
Serwer przesyła dane do klienta, a klient używa certyfikatu do zaszyfrowania klucza do szyfrowania dalszej komunikacji.
### 2.1 Generowanie certyfikatów
Ceryfikat SSL można wygenerować przy pomocy **OpenSSL**. Przemysłowe certyfikaty, mające zaufane organizacje na szczycie **łańcucha poświadczeń** można kupić lub pozyskać bezpłatnie.
Najprostszy serwer HTTPs w node.js:
```javascript
var fs = require('fs');
var https = require('https');
(async function () {
var pfx = await fs.promises.readFile('test.pfx');
var server - https.createServer({
pfx: pfx,
passphrase: 'test'
},
(req, res) => {
res.setHeader('Content-type', 'text/html; charset=utf-8');
res.end('hello world ${new Date()}')
});
server.listen(3000);
console.log('started');
})
```
### 2.2 HTTP/2
rozszerza protokól http o optymalizacje w warstwie transportowej:
- otwiera zawsze **jedno gniazdo** między klientem a serwerem
- ruch jest **kompresowany, binarny**
- możliwe jest **zrównoleglanie wielu żądań i wielu odpowiedzi**
- możliwe jest **przesyłanie danych** z serwera do klienta **zanim klient zrobi żądanie**
### 2.3 Rzeczywistość
W pliku **etc/host** możliwe jest mapowanie DNS na potrzeby lokalnej maszyny. W praktyce oznacza to możliwość zamapowania na lokalny sinterfejs sieciowy **127.0.0.X** dowolnego nagłówka hosta.
W rzeczywistości wykorzystuje się co najmniej dwie warstwy serwerów i tzw. **mechanizm reverse proxy**, w którym ruch trafia do warstwy serwerów frontowych na portach 80/443, a stamtąd do serwerów backendowych, schowanych wewnątrz sieci dostawcy.
### 2.4 Formularz, HTTP POST
Komunikacja zwrotna klienta z serwerem możliwa jest dzięki **formularzom**
> Np.:
> ```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>Document</title>
> </head>
> <body>
> <form method="POST" enctype="application/x-www-form-urlencoded">
> <div>
> Login: <input type='text' name='login' /><br/>
> <button>Login</button>
> </div>
> </form>
> </body>
> </html>
> ```
# Wykład 8
## 1. Express
Najpopularniejszy i najprzystępniejszy framework do wytwarzania w node.js aplikacji niternetowych opartych o klasyczny schemat **Request-Reply**.
Inne podejście - **Single-Page Applications**, gdzie strony nie przeładowują się z każdą interakcją użytkownika (React/Angular)
## 2. Middleware
Funkcja, która obsługuje żądanie i która może delegować częśc pracy do kolejnej funkcji typu middleware. Obsługa żądania może tworzyć łańcuch wywołań:

Celem tego jest rozdzielenie obsługi autentykacji od obsługi renderowania od obsługi błędów itp.
DO obsługi błędów służy przeciążenie funkcji middleware **z czterema argumentami**. Poniżej przykład, gdzie przekazanie błędu wymaga przekazania jednego paramteru do **next**:
```javascript=
var http = require('http');
var express = require('express');
var app = express();
app.use( (req, res, next) => {
if ( true ) //warunek błędu
next('describtion');
else
res.end('poprawne działanie');
});
app.use( (errm req, res, next) => {
res.end( `Error handling request: ${err}`);
});
http.createServer(app).listen(3000);
```
## 3. EJS (Embedded Javascript)
Jeden z wielu silników renderowania dla Express. Zwalnia on z konieczności ręcznego zarządzania szablonami "stron". Wymaga foldera, w którym zapisane są widoki.
Sprawia to, że silnik szablonów jest niezależny od silnika aplikacji.
Konfiguruje się to w ten sposób:
- Konfiguracja silnika renderowania - parametr **view engine**
- Konfiguarcja lokalizacji z widokami - parametr **views**
> ```javascript
> //...
> var app = express();
> app.set('view engine', 'ejs');
> app.set('views', './views');
> //...
> ```
Domyślne rozszerzenie stron **(.ejs)** można zmienić na **.html** z dodatkową prostą konfiguracją
```javascript
app.engine('html', ejs.renderFile);
app.set('view engine', 'html');
```
Najważniejszą cechą EJS jest możliwość mieszania elementów deklaratywnych i imperatywnych wewnątrz widoków, w tym m.in. deklarowanie zmiennych lokalnych
- **<%** i **%>** - ograniczniki struktury imperatywnej
- **<%=** i **%>** - umożliwiają wypisanie wartości
- **<%-** i **%>** - wypisanie wartości zakodowanej (tzw. HTML encoding)
```html
<% var foo = 'bar' %>
<% for ( var i=0; i<5; i++ ) { %>
<div>
Element <%= i %>
</div>
<% } %>
Zmienna foo: <%= foo %>
```
## 4. Dodatkowe elementy architektury aplikacji
### 4.1 Middleware do plików statycznych
Middleware **epxress.static** pozwala określić folder, z którego serwowane są pliki statyczne - w strukturze plików aplikacji jest to zwykle podfolder, ale z punktu widzenia http adresowanie jest względne do roota aplikacji.
### 4.2 Kontrola typu zwracanej odpowiedzi
Za pomocą ustawiania nagłówków możliwe jest kontrolowanie typu odpowiedzi (np. wymuszenie potraktowania odpowiedzi jako pliku do pobrania możliwe jest za pomocą nagłówka Content-disposition)
### 4.3 Obsługa nawigacji między "stronami"
Do przekierowania żądania do innego adresu służy metoda **redirect** obiektu odpowiedzi. Serwer odsyła do przeglądarki status **302 Object moved** z nagłówkiem Location wskazującym na nowy adres. Przeglądarka sama udaje się pod nowy adres z żądaniem typu **GET**

### 4.4 Odczytywanie parametrów przekazanych w pasku adresowym
Odczyt parametrów przekazanych w pasku adresowym możliwy jest za pomocą właściwości **query** obiektu żądania.
### 4.5 Ścieżki dla żądań różnego typu (GET/POST)
Express umożliwia powiązanie funkcji middleware z typem żądania (GET/POST). Zwyczajowo używa się tego do odróżnienia pierwszego żądania, które renderuje zawartość (GET) od kolejnych, które obsługują zwrotnie odesłany formularz (POST)
Odczyt danych z formularza (POST) wymaga dodatkowego middleware, **express.urlencoded**.
# Wykład 9
### Domyślne middleware do obsługi nieobsłużonych ścieżek oraz zagrożenie Cross-Site Scripting
"Domyślne" middleware, dodane jako ostatnie, będzie obsługiwać wszystkie nieobsłużone do tej pory ścieżki.
Użycie znacznika **<%= i %>** chroni aplikację przed zagrożeniem (typu atak polagający na przesłaniu przez atakującego spreparowanego odnośnika zawierającego fragment skryptu do wykonania, np: **http://localhost:3000/foobar<script>window.alert(‘hello’)</script>**)
### Użycie parametrów w ścieżkach i zagrożenie Web Parameter Tampering
Możliwe jest dynamiczne parametryzowanie ścieżek. Sparametryzowana ścieżka dospwuje się do całej klasy ścieżek, a ograniczenie dopasowania polega na możliwości użycia wyrażenia regularnego, (na przykład wymuszającego tylko liczby).
Jednym z typowych mechanizmów ochrony przed tym zagrożeniem jest użycie dodatkowego parametru weryfikującego poprawność odnośnika, wykorzystującego mechanizm HMAC (Hash Message Authentication Code)/
Na serwerze parametr ścieżki adresowej jest łączony z **kluczem tajnym** a otrzymana wartość jest używa jako argument do jednokierunkowej funkcji skrótu.
Wynik jest dodawany do adresu jako jego "podpis", a niezgodność podpisu wyliczonego z oczekiwanym oznacza, że użytkownik **zmodyfikował** wartość parametru.
_____
Inny, prostszy ale nie zawsze możliwy sposób ochrony przed tym zagrożeniem pojawia się gdy link dotyczy **zalogowanego użytkownika** (który na przykład dostał dane z bazy danych powiązanych jakoś ze swoimi danymi).
Czyli - jest zapytanie, które dla zalogowanego użytkownika zwraca listę dozwolonych identyfikatorów i ona pojawia się jako część listy odnośników.
Zatem sprwadzane są warunki:
- użytkownik niezalogowany - zwracana informacja o błędzie
- użytkownik zalogowany - zapytanie wyciągające zbiór identyfiaktorów jest powtarzane a nasepnie sprawdza się czy przychodząca wartość parametru znajduje się w zbiorze:
- nie znajduje się - zwracana informacja o błędzie
- znajduje się - zwracamy dane
## Obsługa ciasteczek
Używa się middleware **cookie-parser**.
# Wykład 13
## 1. Trochę SQLa
### 1.1 SELECT
* Do pobrania danych z tabeli służy zapytanie typu `SELECT`
```sql=
SELECT * from Parent
```
* Zbiór wynikowy może być dodatkowo ograniczony klauzulą `WHERE`
```sql=
SELECT * from Parent WHERE ParentName='parent1'
```
* Klauzul może być wiele i mogą tworzyć całe wyrażenie logiczne, tutaj wybieramy wszystkie wiersze leżące pomiędzy tymi dwoma
```sql=
SELECT * from Parent WHERE 'parent'<ParentName AND ParentName<'parent1'
```
* Zbiór może być dodatkowo uporządkowany za pomocą `ORDER BY`
```sql=
SELECT * from Parent WHERE 'parent'<ParentName AND ParentName<'parent1'
ORDER BY ParentName
```
## 1.2 INSERT
Dodawanie danych do tabeli możliwe jest za pomocą zapytania typu `INSERT`.
* To zapytanie wstawia nowy wiersz do tabeli Parent i przypisuje wartość 'Parent1' do kolumny ParentName
```sql=
INSERT INTO Parent (ParentName) VALUES ('Parent1')
```
Z kolei w sytuacji gdy jako generator wartości klucza głównego służy sekwencja mamy:
```sql=
CREATE SEQUENCE sequence_name START WITH 1 INCREMENT BY 1;
```
* Wstawianie rekordów z użyciem sekwencji
```sql=
INSERT INTO Parent (Imie, Nazwisko, Plec) VALUES ('Jan', 'Kowalski', 'M');
```
## 1.3 UPDATE/DELETE
* Do modyfikacji rekordów służy zapytanie typu UPDATE np.
```sql=
UPDATE Parent SET ParentName='new name' WHERE ID=1
```
* Do usuwania rekordów – DELETE
```sql=
DELETE FROM Parent WHERE ID=1
```
#TODO