REST palvelun pystytys

Yleistä RESTistä

REST-palvelu on yleinen tapa toteuttaa tietopalvelun rajapinta web-palvelulle. REST-palvelu on ulospäin itse asiassa kuin ”perinteinen” HTTP-palvelu ja REST-rajapinta vastaa samoihin pyyntöihin kuin perus HTTP-palvelin. Myös HTTP -statuskoodit ovat käytössä eli onnistunut REST-palvelupyynnön käsittely palauttaa statuskoodin 200 OK, epäonnistunut tiedonhaku (vaikkapa haku id:llä jota ei löydy tietokannasta) palauttaa statuskoodin 404  Not found, jne.

Erona perus HTTP-palvelimeen/palveluun on, että paluuviestinä ei saada HTML-sivua vaan tyypillisesti JSON-muotoinen vastaus. Formaatti REST-palvelussa on tyypillisesti JSON mutta voisi olla myös XML. JSON on helposti hyödynnettävissä JavaScriptissä ja se voidaan tallentaa ilman muunnosta suoraan no-sql tietokantaan (esim. MongoDB) joten se on kätevä ja suosittu formaatti.

REST verbit (=metodit)

Seuraavassa esitellään yleinen REST-palveluiden käyttämä HTTP-verbien käyttötapa. Kyseessä on siis yleinen käytäntö, mutta ei tietenkään pakollinen ”sapluuna” vaan palvelun toteuttaja päättää millaisella käytännöllä palvelua käytetään.

GET    Tietopyyntö jolla haetaan tallennettua dataa. Esimerkiksi pyyntö GET http://palvelu.net/asiakkaat palauttaa listan asiakkaista. Pyynnössä voidaan myös yksilöidä, mikä datayksilö halutaan hakea. Silloin osoitteeseen lisätään haettavan tietueen id, esimerkiksi GET http://palvelu.net/asiakkaat/f310e311-93e5-43ae-be0a-71628a147b90.

POST     Tiedon tallennus. Esimerkiksi osoitteeseen http://palvelu.net/asiakkaat postattu JSON muotoinen sisältö {”nimi”:”Aku Ankka”, ”address”: ”Paratiisitie 13”} tallettaisi Aku Ankan asiakastietoihin. Paluuviestissä saadaan tallennettu tietue varustettuna id:llä, jos tallennus onnistui.

PUT    Tiedon päivitys eli update. Palvelupyynnön mukana annetaan taas tiedot kuten POST-pyynnössä mutta tällä kertaa mukana on tietueen id, jotta päivitys osataan kohdistaa ko. riviin. Esim. PUT http://palvelu.net/asiakkaat/f310e311-93e5-43ae-be0a-71628a147b90 ja content osiossa tietueen tiedot {”nimi”:”Aku Ankka”, ”address”: ”Hanhivaaranpolku 22”} .

DELETE    Tiedon poisto. Luonnollisesti yleensä järkevä vain kun kohdistetaan tiettyyn tietoriviin, id:llä osoitettuna, esim. DELETE http://palvelu.net/asiakkaat/f310e311-93e5-43ae-be0a-71628a147b90. Mikään ei tietysti estä toteuttamasta DELETE-operaatiota myös osoitteelle http://palvelu.net/asiakkaat siten että pyyntö poistaisi kaikki asiakastiedot, mutta tämä ei yleensä liene kovin järkevää.

Muitakin HTTP-verbejä voidaan käyttää, mutta yllä ehkä tärkeimmät.

Tarkemmin REST verbeistä esim. täältä:

http://www.restapitutorial.com/lessons/httpmethods.html

REST palvelun testaustyökalu selaimeen

Olemassa olevia REST-palveluita on helpointa testata selaimeen asennetun POSTER-lisäosan avulla. Kun selaimeen asentaa POSTER lisäosan (tällä nimellä löytyy ainakin Firefoxiin ja Cromeen) niin selaimen valikosta saa kätevästi käyntiin testerin jolla voi tehdä pyyntöjä REST-palveluihin ja tarkastella saatua vastausta. Alla kuva Firefoxissa toimivasta POSTER add-onista:

poster

Posterilla on helppo lähettää REST-palveluun erityyppisiä pyyntöjä ja katsoa mitä tulee vastaukseksi.

Latauslinkki : POSTER AddOn for Firefox:

https://addons.mozilla.org/en-US/firefox/addon/poster/

Työkalu käynnistyy Firefoxin Tools-valikosta.

REST-palvelun toteutus Node.js:llä

Toteutamme seuraavaksi yksinkertaisen REST-palvelun joka vastaa POST, GET ja DELETE pyyntöihin, tallentaen ja hakien dataa JSON-muodossa. GET ilman parametreja palauttaa kaikki tietoalkiot tai jos parametrina annetaaan id, palautetaan alkio kyseisellä id:llä. POST generoi alkiolle uuden id:n, tallentaa alkion palvelun sisäiseen taulukkoon ja lopuksi palauttaa alkion id:llä varustettuna takaisin kutsujalle. DELETE poistaa tiedot annetulla id:llä.

Palvelun toteutus olettaa että Node.js:lle on ladattu expess ja body-parser kirjastot.

var express = require('express');   // for easy HTTP server
var application = express();

var bodyParser = require('body-parser');
application.use(bodyParser.urlencoded({
    extended: true
}));
application.use(bodyParser.json());

// this is needed to allow connection from any address:
application.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  res.header("Access-Control-Allow-Methods", "GET,POST,DELETE"); // PUT is not implemented
  next();
});

// array to store items
var items = [];

// POST
application.post('/items/', function (req, res) {
   console.log('POST received'); 
   console.log(req.body);
   var item = req.body;
   var id = generateGuid();
   item.id  = id;
   console.log(id);
   items.push(item);
   var responseItem = JSON.stringify(item);
   res.end(responseItem);
});

// This is one way to generate new id
function generateGuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
}

// GET: get all items
application.get('/items/', function (req, res) {
    console.log('GET all received'); 
   var responseItems = JSON.stringify(items);
   res.end(responseItems);
});

// GET: get item(s) with id
application.get('/items/:id', function (req, res) {
    console.log('GET with id received'); 
    var filtered = items.filter(x => x.id==req.params.id);
    var responseJSON = JSON.stringify(filtered);
    res.end(responseJSON);
});

// DELETE: delete item(s) ith id
application.delete('/items/:id', function(req, res) {
    console.log('DELETE with id received');   
    items = items.filter(i=>i.id!=req.params.id);
    res.send({success : true});
});

// Start server
var server = application.listen(8080, function () {
  var port = server.address().port;
  console.log('Simple REST API listening on port %s', port);
});

Seuraavaksi käynnistetään yllä toteutettu palvelu komentoriviltä:

srs_start

Sitten käynnistetään testaustyökalu eli POSTER lisäosa selaimesta.

Ensimmäinen palvelupyyntö on uuden tiedon tallennus POST metodilla jonka vastauksena saadaan 200 OK ja tallennettu tieto id:llä varustettuna:

srs_post

Tallennetaan saman tien toinen tieto:

srs_post2

Sitten haetaan tiedot GET pyynnöllä ja vastauksena saadaan kaksi tietoalkiota:

srs_get

Kokeillaan poistaa toinen tietoalkio DELETE pyynnöllä (huomaa id parametrina urlissa):

srs_delete

Kun nyt tehdään vielä yksi GET pyyntö, nähdään että toinen tietoalkio on poistunut palvelimelta:

srs_get2

Yhteenvetona voidaan todeta että Node.js:llä on todella helppo pystyttää yksinkertainen REST-palvelu joka käyttää JSON formaattia tiedon välittämiseen.