Java týden
Procvič si angličtinu zdarma s naším americkým e-learningem! Learn more
Pouze tento týden sleva až 80 % na celý Java e-learning!

Lekce 4 - Kompletní RESTful API v Node.js

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Rozběhnutí projektu a první řádky v Expressu, jsme si připravili pracovní prostředí a začali jsme používat knihovnu Express. Dnes v tutoriálu implementujeme kompletní RESTful API v Node.js pro databázi filmů. Cestou se naučíme používat několik užitečných nástrojů.

Založení projektu

Minule jsme si pomocí npm založili projekt a nainstalovali express. Pro dnešní aplikaci si vytvoříme nový projekt. Pro jistotu si ještě jednou uveďme příslušné příkazy:

mkdir node-projekt
cd node-projekt
npm init --yes
npm install express

V projektu poté jako minule do nového souboru index.js napíšeme následující kód:

const express = require('express');
const app = express();

app.listen(3000, () => console.log('Listening on port 3000...'));

Nodemon

Pokud jste minule během čtení článku psali i kód, mohlo vás otravovat, že při každé úpravě kódu bylo potřeba aplikaci restartovat. Nástroj nodemon nabízí lepší řešení. Nodemon je zkratka za node monitor. Hlídá všechny soubory typu .js (a pár dalších typů) v dané složce a podsložkách. Kdykoli se některý z těchto souborů změní, nodemon aplikaci sám restartuje. Veškeré změny tak můžeme rovnou vyzkoušet.

Nodemon nainstalujeme opět pomocí npm. Většinou ho chceme nainstalovat globálně, s použitím parametru -g. Pak již jen stačí zadat do příkazové řádky místo příkazu node index.js příkaz nodemon index.js:

npm install -g nodemon
nodemon index.js

Metoda GET

Metodu GET jsme používali již minule. Nově bude vracet všechny filmy nebo detail jednoho konkrétního filmu. K tomu budeme samozřejmě nejdříve potřebovat databázi filmů.

Příprava dat

Pro začátek nebudeme ještě používat databázi (tu si přidáme v některé z příštích lekcí), ale budeme filmy držet v poli.

const movies = [
    { id: 1, name: "Kill Bill", year: 2003 },
    { id: 2, name: "Kill Bill 2", year: 2004 },
    { id: 3, name: "Star Wars IV", year: 1976 },
    { id: 4, name: "Star Wars V", year: 1980 }
];

O filmech bychom mohli uchovávat mnohem více dat (a v databázi také budeme), zatím nám však postačí id, jméno filmu a rok premiéry.

Implementace metody GET pro vás nebude těžká, pokud jste dobře četli předchozí lekci. Přehled cest jsme si udělali již ve druhé lekci a metodu GET už umíme:

app.get('/api/movies', (req, res) => {
    res.send(movies);
});

app.get('/api/movies/:id', (req, res) => {
    const id = Number(req.params.id);
    const movie = movies.find( movie => movie.id === id);
    if (movie) {
        res.send(movie);
    } else {
        res.status(404).send('Film nebyl nalezen.');
    }
});

V prvním volání metody app.get() bez parametru se ptáme na všechny filmy, vrátí se tedy celé pole. Při druhém volání požíváme parametr id, pomocí metody find() na vyhledávání v poli najdeme správný film a vrátíme ho. Pokud by film neexistoval, vrátíme chybovou hlášku a HTTP kód 404 Not Found (požadovaný dokument nebyl nalezen).

Nyní již aplikaci nemusíte restartovat, stačí kód uložit. Po zadání http://localhost:3000/api/movies do adresního řádku se zobrazí seznam filmů:

Your page
http://localhos­t:3000/api/mo­vies

Nebo můžete přidat ještě jedno lomítko a id filmu, zobrazí se jen data o konkrétním filmu.

Your page
http://localhos­t:3000/api/mo­vies/1

Zkuste si zadat i id, pro které film neexistuje, zobrazí se chybová hláška (a ve vývojářských nástrojích pod klávesou F12 se v panelu "Network" můžete přesvědčit, že vám server vrátil kód 404).

Metoda POST

Určitě jste si všimli, že se pole s filmy v prohlížeči nezobrazilo moc hezky. Prohlížeč je totiž určený pro vykreslování webových stránek, ne pro zobrazování polí. Požadavek s metodou POST bychom dokonce měli problém i odeslat.

Postman

Proto se hodí mít aplikaci, která nám umožní posílat všechny typy požadavků. Jednou takovou je Postman. Stáhněte si ho z www.getpostman.com. Instalaci určitě zvládnete sami.

Posílání POST požadavku na Node server v aplikaci Postman

Po spuštění zvolíme metodu GET (1), do adresního řádku napíšeme totéž co do adresního řádku prohlížeče (2), a klikneme na tlačítko "Send" (3).

Zobrazí se nám seznam filmů nebo konkrétní film, podle toho, s jakou cestou jsme požadavek poslali. Kromě toho nám Postman ukazuje HTTP kód 200 OK, se kterým odpověď přišla (4) a mnoho dalších informací.

Můžete si ještě vyzkoušet, že vrátí kód 404 při zadání GET požadavku na neexistující id filmu. Stejně jako v prohlížeči si v něm můžete vytvářet záložky na různé požadavky pomocí tlačítka + (5).

Od teď už budeme všechny požadavky na naše API posílat pomocí Postmana.

Implementace POST

Když máme Postmana, můžeme si naimplementovat metodu POST. Do index.js vložme následující kód (a soubor uložme):

app.post('/api/movies', (req, res) => {
    const movie = {
        id: movies.length + 1,
        name: req.body.name,
        year: req.body.year
    };
    movies.push(movie);
    res.send(movie);
});

Nyní voláme metodu app.post(). Požadavek posíláme na cestu bez parametru, protože id nový film ještě nemá přiřazený. Nyní ho tvoříme jako délku pole plus jedna. (To nemusí být vždycky správně, ale vzhledem k tomu, že časem to za nás bude dělat databáze, tak nám to protentokrát bude stačit.) Pak už jen přidáme film do databáze a také ho zobrazíme jako odpověď (v odpovědi se zobrazí včetně nově vytvořeného id).

Aby kód fungoval, musíme na začátek souboru (hned po tom, co definujeme konstantu app) přidat ještě tento řádek:

app.use(express.json());

Tím voláme takzvané middleware, což jsou procesy, které se spouští mezi přijetím požadavku a odesláním odpovědi (jsou uprostřed, proto middleware). Konkrétně express.json() parsuje tělo požadavku, a pokud v něm najde nějaký JSON, tak s ním naplní hodnotu vlastnosti req.body. Bez tohoto middleware bychom v req.body nic nenašli.

Nyní již můžeme přejít do Postmana a na nové záložce (1) založit nový požadavek. Metoda bude POST (2), vyplníme adresu, nastavíme tělo požadavku (3), vybereme raw (4) a typ JSON (5).

Do těla požadavku vyplníme šestý díl Star Wars, který nám v původním seznamu chyběl. Nezapomeňte, že vše musí být přesně podle formátu JSON, tedy i jména vlastností musí být v uvozovkách. A můžeme požadavek poslat kliknutím na tlačítko "Send".

Odeslání požadavku pomocí aplikace Postman na Node.js API server

Validace

Je to trochu odbočka, ale je to tak důležité, že to nelze nezmínit:

Vždy ověřujte, jestli data, která vám někdo posílá, jsou v pořádku a odpovídají tomu, co očekáváte.

Zatím si posíláte do své aplikace data sami, z Postmana, takže si nebudete úmyslně posílat špatná data. Ale jste si jistí, že tam nemáte žádný překlep? A co když bude data posílat někdo cizí?

Rychlou validaci si můžete napsat sami - stačilo by ověřit, že jméno filmu je řetězec a rok premiéry je číslo. Ale opět - časem budeme potřebovat komplexnější validaci, a proč psát spoustu kódu navíc, když na ni už existují hotové balíčky? Jeden z nich, velmi oblíbený, se jmenuje Joi.

Nainstalujeme si ho pomocí npm:

npm install joi

Na začátek index.js přidejme následující kód:

const Joi = require('joi');

To, co se nám vrací při použití require(), je třída, proto velké J.

Na konec souboru přidejme funkci validateMovie():

function validateMovie(movie) {
    const schema = {
        name: Joi.string().min(3).required(),
        year: Joi.number()
    };
    return Joi.validate(movie, schema);
}

Ve funkci validateMovie() definujeme schéma, které říká, že jméno bude řetězec o minimální délce tří znaků a je povinné. Rok musí být číslo a povinný není. Potom pomocí metody Joi.validate() porovnáme JSON z těla požadavku (parametr movie) s uvedeným schématem.

Metodu app.post() pak můžeme upravit třeba takto:

app.post('/api/movies', (req, res) => {
    const { error } = validateMovie(req.body);
    if (error) {
        res.status(400).send(error.details[0].message);
    } else {
        const movie = {
            id: movies.length + 1,
            name: req.body.name,
            year: req.body.year
        };
        movies.push(movie);
        res.send(movie);
    }
});

Pokud požadavek neodpovídá schématu, vrací se nám objekt s vlastností error. V tomto případě vrátíme uživateli chybovou hlášku, kterou nám připravil Joi, spolu s HTTP kódem 400 Bad Request. Pokud je vše v pořádku, vlastnost error v objektu neexistuje a zbylý kód proběhne stejně jako předtím.

Zkuste si teď poslat z Postmana několik POST požadavků s validními nebo se špatnými daty a sledujte chování aplikace.

Metoda PUT

Pokud jste filmoví znalci, jistě vám neuniklo, že máme v kódu špatný rok u čtvrtého dílu Star Wars. Pojďme ho tedy opravit - naučíme naše API obsluhovat metodu PUT.

Do index.js vložme následující kód (a soubor nezapomeňme uložit):

app.put('/api/movies/:id', (req, res) => {
    const id = Number(req.params.id);
    const movie = movies.find(movie => movie.id === id);
    if (!movie) {
        res.status(404).send('Film nebyl nalezen.');
        return;
    }
    const { error } = validateMovie(req.body);
    if (error) {
        res.status(400).send(error.details[0].message);
    } else {
        movie.name = req.body.name;
        movie.year = req.body.year;
        res.send(movie);
    }
});

Opakují se tu věci, co jsme již použili v jiných metodách, takže není třeba kód znovu vysvětlovat. Přejdeme opět do Postmana, na nové záložce vybereme metodu PUT, pošleme ji na koncový bod http://localhost:3000/api/movies/3 a do těla vložíme následující JSON:

{
    "name": "Star Wars IV",
    "year": 1977
}

Nezapomeňte vybrat raw a typ JSON. A pak jen ověřte, pomocí GET požadavku, že filmy již mají správně nastavený rok premiéry.

Metoda DELETE

A zbývá nám metoda DELETE. To už teď bude jednoduché:

app.delete('/api/movies/:id', (req, res) => {
    const id = Number(req.params.id);
    const movie = movies.find(movie => movie.id === id);
    if (!movie) {
        res.status(404).send('Film nebyl nalezen.');
    } else {
        const index = movies.indexOf(movie);
        movies.splice(index, 1);
        res.send(movie);
    }
});

Kódu už určitě rozumíte. Nezapomeňte si pomocí Postmana poslat DELETE požadavek, abyste otestovali, že to opravdu funguje.

Příště, v lekci Úvod do MongoDB, si povíme něco o databázích a hlavně o MongoDB.

Opět poznámka na závěr: ES6 object destructuring

Pokud jste si nevěděli rady s proměnnou error deklarovanou ve složených závorkách, jedná se tzv. object destructuring. Místo vysvětlování vám raději ukážu krátký kód:

const obj = {
    a: 1,
    b: 2,
    c: 3
};
const { a, b } = obj;

V konstantách a a b budou uložena data, která se přečtou zevnitř objektu. Tedy v a bude po proběhnutí kódu uložena jednička a v b dvojka.


 

Stáhnout

Staženo 25x (1.27 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

 

Aktivity (9)

 

 

Komentáře

Avatar
Míla Skipper Moravec:26. dubna 18:28

Stále jsem přemýšlel, proč mi nefunguje metoda POST. A odpověď je, že na tvým řádku máš

app.post('api/movies', (req, res) => {

ale má být

app.post('/api/movies', (req, res) => {
 
Odpovědět 26. dubna 18:28
Avatar
Odpovídá na Míla Skipper Moravec
Petr Sedláček:26. dubna 18:38

Vidíš, díky!
Opravím to.

 
Odpovědět 26. dubna 18:38
Avatar
jindrich.jokel:15. května 13:50

super clanky bruh, planuje i nejake dalsi pokracovani?

 
Odpovědět 15. května 13:50
Avatar
Lukáš Korel:5. srpna 12:38

Jde nějak získat více parametrů při volání GET?, kdybych chtěl vracet objekt, jehož vyhledání závisí na 2 parametrech (pro jednoduchost výpočet obsahu obdélníku, API by bralo 2 parametry např. http://localhost:3000/…ngle/a=2,b=3 (nebo jak jinak to zapsat)

Děkuji za informaci

 
Odpovědět 5. srpna 12:38
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 4 zpráv z 4.