Slide 1

Slide 1 text

Restify moduł Node.js do tworzenia webserwisów REST Adam Jodłowski

Slide 2

Slide 2 text

2 Co to jest Node.js?

Slide 3

Slide 3 text

3 Node.js ● środowisko uruchomieniowe JavaScript na serwerze ● przeznaczone dla nowoczesnych aplikacji nastawionych na bogatą interakcję z klientem ● zorientowane na zdarzenia (event loop) ● jednowątkowość wymusza nieblokujące operacje I/O ● podstawą projektu jest silnik JavaScript Google V8, kilka wbudowanych bibliotek i moduły użytkowników ● implementuje ECMAScript 5, część standardu CommonJS i dostarcza konsolę REPL

Slide 4

Slide 4 text

4 Co to jest REST?

Slide 5

Slide 5 text

5 REpresentational State Transfer ● paradygmat tworzenia usług klient-serwer zainspirowany sposobem działania protokołu HTTP ● opiera się na pojęciu reprezentacji zasobu i możliwych do wykonania na nim metod zmieniających jego stan ● główne cechy ● architektura klient-serwer ● zorientowanie na zasoby ● jednolity interfejs ● bezstanowość

Slide 6

Slide 6 text

6 Do rzeczy

Slide 7

Slide 7 text

7 Restify v1.3 ● moduł Node.js ułatwiający tworzenie poprawnych usług sieciowych zgodnych z paradygmatem REST ● opracowany z myślą o lepszej kontroli nad HTTP niż dają to frameworki webowe (np. Express) ● zawiera szereg udogodnień (wersjonowanie, sumy kontrolne, filtry) dla tworzenia tzw. strict APIs

Slide 8

Slide 8 text

8 Instalacja i uruchomienie $ npm install restify var restify = require('restify'); var server = restify.createServer(); server.listen(8080, function() { console.log('%s listening at %s', server.name, server.url); }); function respond(req, res, next) { res.send('hello ' + req.params.name); } server.get('/hello/:name', respond); $ node server.js restify listening at http://0.0.0.0:8080

Slide 9

Slide 9 text

9 Sprawdzenie, czy działa $ curl -is http://localhost:8080/hello/adamus -H 'Accept: text/plain' HTTP/1.1 200 OK Access-Control-Allow-Origin: * Access-Control-Allow-Headers: Accept, Accept-Version, Content-Length, Content- MD5, Content-Type, Date, X-Api-Version Access-Control-Expose-Headers: X-Api-Version, X-Request-Id, X-Response-Time Server: restify X-Request-Id: 06ace5a0-87ab-4faf-b76c-9a9a35682937 Access-Control-Allow-Methods: GET Connection: close Content-Length: 12 Content-MD5: TNyTQnhx7KlWEKi+aTn9zA== Content-Type: text/plain; charset=UTF-8 Date: Thu, 15 Mar 2012 12:24:49 GMT X-Response-Time: 3 hello adamus // domyślny Content-Type to application/json

Slide 10

Slide 10 text

10 Przegląd możliwości

Slide 11

Slide 11 text

11 Konfiguracja i wspólne handlery żądań Obiekt konfiguracyjny używany przy tworzeniu serwera var fs = require('fs'); var options = { certificate: fs.readFileSync('certificate.crt'), key: fs.readFileSync('private.key'), name: 'Restify Server 1.0', version: '1.0.0', // X-Api-Version: 1.0.0 formatters: { 'format': function() { ... } } }; var server = restify.createServer(options); Obsługa żądań przed lub po wywołaniu metod rutingu server.pre(function (req, res, next) { // server.pre([f1, f2, ...]); // przetwarzanie ... return next(); }); // kolejność wywołania zależna od kolejności rejestracji względem rutingu server.use(function (req, res, next) { ... });

Slide 12

Slide 12 text

12 Ruting Ruting oparty jest o metody dostępu i ścieżki zasobów, parametry w formie URL-encoded lub JSON są automatycznie parsowane server.get('/posts/:id', function (req, res, next) { console.log('post id = ' + req.params.id); res.send(200, {author: 'adamus', content: 'this is a post'}); return next(); }); $ curl http://localhost:8080/posts/8 {"author":"adamus","content":"this is a post"} // komunikat konsoli serwera: post id = 8 Pozostałe metody obsługujemy analogicznie server.post(...); server.put(...); server.del(...); server.head(...); W miejsce ścieżki możemy przekazać obiekt RegExp a dopasowania kolejnych grup otrzymamy w req.params[0], req.params[1] itd.

Slide 13

Slide 13 text

13 Wersjonowanie rutingu Protokół HTTP nie definiuje sposobu wersjonowania RESTfulowych API, przyjęto zatem rozwiązanie Semantic Versioning (SemVer) server.get({path: '/posts/:id', version: '2.0.1'}, function (req, res, next) { ... }); server.get({path: '/posts/:id', version: '1.2.3'}, function (req, res, next) { ... }); $ curl localhost:8080/posts/8 -H 'Accept-Version: 1' // otrzymamy wersję 1.2.3 $ curl localhost:8080/posts/8 // otrzymamy pierwszą zarejestrowaną wersję, czyli 2.0.1 $ curl localhost:8080/posts/8 -H 'Accept-Version: 3' HTTP/1.1 400 Bad Request {"code":"InvalidVersion","message":"GET /posts/8 supports versions: 2.0.1, 1.2.3"} W powyższych ścieżkach możemy podać tablice kolejnych wersji W taki sam sposób działa parametr version całego serwera, ale dotyczy wszystkich ścieżek, którym nie nadano wersji (pełni rolę domyślną)

Slide 14

Slide 14 text

14 Negocjacja reprezentacji treści Wysyłając odpowiedź metodą send() wartość nagłówka Content-Type może być ustalona automatycznie na podstawie dostępnych formaterów, wbudowano obsługę application/octet-stream*, application/json i text/plain Własne formatery treści podajemy w konfiguracji serwera formatters: { 'application/my-format': function (req, res, body) { // logika konwersji formatu return reprezentacja_body; } // kolejne formatery ... } Wysyłając żądanie z określonym formatem w nagłówku Accept, zostanie odesłana postać zwrócona w funkcji obsługi tego formatu Obsługiwane przez serwer formaty znajdują się w tablicy server.acceptable

Slide 15

Slide 15 text

15 Obsługa błędów Nieobsłużone błędy powodują zwrócenie kodu 500 Możemy zwracać błędy pierwszym argumentem liczbowym metody send() oraz korzystać z obiektu Error('wiadomość') res.send(401, new Error('Nie masz uprawnień')); Restify posiada zestaw symbolicznych błędów HttpError i RestError (niestandardowe błędy z dodatkowym opisem w postaci JSON) return next(new restify.ConflictError("Żądanie jest konfliktowe")); // HttpError return next(new restify.InvalidArgumentError("Niepoprawny argument")); // RestError // obie instrukcje zwrócą kod 409

Slide 16

Slide 16 text

16 Zdarzenia rozgłaszane (EventEmitter) Restify rozgłasza standardowe zdarzenia z modułu http.Server Node.js oraz własne, takie jak: ● 'NotFound' ● 'MethodNotAllowed' ● 'VersionNotAllowed' ● 'after' ● 'uncaughtException' Nasłuchujemy na zdarzenia przez server.on('zdarzenie', funkcja_obsługi(...) { ... });

Slide 17

Slide 17 text

17 Wbudowane pluginy Restify dostarcza kilka pluginów do przetwarzania żądań ● AcceptParser ● QueryParser ● BodyParser ● Throttle (token bucket) ● ConditionalRequest ● ETag / If-None-Match ● LastModified / If-Modified-Since ● AuditLogger

Slide 18

Slide 18 text

18 Obiekt żądania Do standardowych właściwości z http.ServerRequest (method, url, headers) Restify dodaje własne .header('Authorization') – pobranie wartości nagłówka .accepts('text/plain') – czy żądanie akceptuje format .is('application/json') – czy żądanie jest danego typu .contentLength, .contentType .id – UUID żądania .time – czas dotarcia do serwera .secure – czy żądanie przyszło w sesji SSL

Slide 19

Slide 19 text

19 Obiekt odpowiedzi Do standardowych właściwości z http.ServerResponse (statusCode, get/set/removeHeader) Restify dodaje własne .header('X-My-Header', '...') – ustawienie wartości nagłówka .cache(typ, opcje) – ustawienie nagłówka Cache-Control .status(200)/.code – ustawienie kodu odpowiedzi .contentLength, .contentType .charSet – kodowanie dopisywane do Content-Type .id – UUID żądania Możemy nadpisać domyślnie odsyłane nagłówki i ich treść restify.defaultResponseHeaders = function(data) { this.header('Server', 'Mój serwer'); }; // this to obiekt odpowiedzi a data to gotowe do wysłania ciało (response body)

Slide 20

Slide 20 text

20 Bonus: strona kliencka

Slide 21

Slide 21 text

21 Restify Client Moduł kliencki pozwala konsumować usługi sieciowe ● JsonClient ● wysyła i odbiera wiadomości w formacie JSON ● StringClient ● wysyła Url-Encoded i odbiera czysty tekst, na przykład XML ● HttpClient ● umożliwia pracę ze strumieniami danych na poziomie oferowanym przez moduły http/https Node.js Konfiguracja żądań obejmuje metodę dostępu, nagłówki, czas timeoutu, liczbę powtórzeń wywołania itp.

Slide 22

Slide 22 text

22 Same zalety?

Slide 23

Slide 23 text

23 Problemy z Restify ● Nieaktualna i niedokładna dokumentacja ● Brak obsługi niestandardowych metod HTTP ● Brak negocjacji Accept-Charset, -Encoding*, -Language ● Brak obsługi nietrywialnych metod autoryzacji ● Niespójne API Rozwiązanie? Fork me on GitHub

Slide 24

Slide 24 text

24 Dla zainteresowanych

Slide 25

Slide 25 text

25 Warto poczytać ● Just what is Node.js? http://www.ibm.com/developerworks/opensource/library/os-nodejs/ ● What is Node.js? http://radar.oreilly.com/2011/07/what-is-node.html ● Nobody Understands REST or HTTP http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http ● Some People Understand REST and HTTP http://blog.steveklabnik.com/posts/2011-08-07-some-people-understand-rest-and-http ● How I Explained REST to My Wife http://tomayko.com/writings/rest-to-my-wife ● Restify documentation http://mcavage.github.com/node-restify/ ● RESTful Web Services Cookbook Subbu Allamaraju, O’Reilly 2010, Yahoo! Press