$30 off During Our Annual Pro Sale. View Details »

Restify

 Restify

Prezentacja i omówienie możliwości frameworku Restify do tworzenia RESTful webservices w oparciu o Node.js.

Adam Jodłowski

July 29, 2012
Tweet

More Decks by Adam Jodłowski

Other Decks in Programming

Transcript

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

    View Slide

  2. 2
    Co to jest Node.js?

    View Slide

  3. 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

    View Slide

  4. 4
    Co to jest REST?

    View Slide

  5. 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ść

    View Slide

  6. 6
    Do rzeczy

    View Slide

  7. 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

    View Slide

  8. 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

    View Slide

  9. 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

    View Slide

  10. 10
    Przegląd możliwości

    View Slide

  11. 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) { ... });

    View Slide

  12. 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.

    View Slide

  13. 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ą)

    View Slide

  14. 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

    View Slide

  15. 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

    View Slide

  16. 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(...) { ... });

    View Slide

  17. 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

    View Slide

  18. 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

    View Slide

  19. 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)

    View Slide

  20. 20
    Bonus: strona kliencka

    View Slide

  21. 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.

    View Slide

  22. 22
    Same zalety?

    View Slide

  23. 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

    View Slide

  24. 24
    Dla zainteresowanych

    View Slide

  25. 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

    View Slide