Pokazywanie postów oznaczonych etykietą nodejs. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą nodejs. Pokaż wszystkie posty

niedziela, 17 marca 2013

[NoSQL] MongoDB + Node.js: mongoose

Interesującą konfiguracją dla aplikacji webowych jest Node.js jako serwer http udostępniający RESTowe API oraz MongoDB jako baza danych. Za takim pomysłem przemawia przede wszystkim format danych: klient przysyła JSONa, Node.js automatycznie parsuje go do obiektu JavaScript na którym można wykonać pewne operacje a później zapisać w bazie jako JSON znowu.

Klientem MongoDB w Node.js jest mongoose. Można go pobrać z menadżera pakietów poleceniem

npm install mongoose

Po dodaniu pakietu do serwera Node.js przy użyciu konstrukcji require, można rozpocząć pracę z MongoDB. Pakiet mongoose do CRUDowych operacji wykorzystuje obiekty typu Schema. Definiując taki obiekt podajemy jakiego typu pola znajdować się będą w naszych dokumentach. Dzięki temu, wstawiając dokument do bazy mamy pewność, że wstawione zostaną jedynie te pola, które zdefiniowaliśmy w schemacie. Mechanizm ten jest konfigurowalny poprzez opcję strict. Jeżeli ustawimy ją na false, to do bazy trafiać będą całe dokumenty. Jeden schemat mapowany będzie na jedną kolekcję w bazie przy zachowaniu zasad języka angielskiego. Na przykład schemat Car zmapowany zostanie do kolekcji cars. Poniżej prosta konfiguracja:
var mongoose = require('mongoose');
mongoose.connect('localhost','mongoosetest');

var schema = mongoose.Schema({ 
    make: 'string',
    enginePower : 'number'
 }, {strict: false});

var Car = mongoose.model('Car', schema);

Dodawanie dokumentów do bazy przy odbieraniu wiadomości typu POST:
app.post('/store/', function(req, resp) {
    var nm = req.body.name;
    var pw = req.body.enginePower;
    var car = new Car({ make: nm, enginePower: pw, day: "17-03" });
    car.save(function(err){
        if(err){
            resp.send({
                ok: 'sth went wrong'
            });
        }
        else{
            resp.send({
                ok: 'everything is fine'
            });
        }       
    });    
});

Analogicznie pobieranie danych wykonujemy także na obiekcie modelu;
app.get('/store/:key', function(req, resp) {
    Car.find({make: req.params.key}, function(err, docs){
        if(err)
            resp.send(501);
        else
            resp.send(docs);
    })
});

Funkcja find może przekazywać bardziej skomplikowane zapytania MongoDB, te same, które dostępne są w shellu bazy (program mongo.exe).

Z kolei aby usunąć obiekt, używamy funkcji remove wołanej również na modelu. Jako pierwszy parametr podaje się warunek.
app.del('/store/:key', function(req, resp) {
    Car.remove({make: req.params.key}, function(err, docs){
        if(err)
            resp.send(500);
        else
            resp.send(200);
    });
});

piątek, 22 lutego 2013

[HTML|JS|CSS] Node.js: WebSockets

WebSockety to ciekawa technologia wykorzystywana w modelu klient - serwer. Zasada działania jest bardzo prosta. Pomiędzy przeglądarką a serwerem otwierany jest dwukierunkowy kanał komunikacji. Obie strony mogą wysyłać wiadomości bez konieczności odpytywania się nawzajem, a także przetwarzać otrzymane wiadomości na zasadzie obsługi zdarzeń. Zgodnie ze specyfikacją, adresy uri dla websocketów zaczynają się od ws lub wss (dla połączeń szyfrowanych).

Implementując WebSockety w Node.js, najwygodniej jest skorzystać z modułu ws. Obsługa połączenia a także wiadomości tradycyjnie wykonywana jest w callbackach, przy czym należy pamiętać że callback dla wiadomości zagnieżdża się w callbacku obsługi połączenia.

var ws = require('ws');
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({port: 9002});

wss.on('connection', function(ws) {
 ws.on('message', function(message) {  
  var date = new Date();
  var str = date.toLocaleDateString() + ' ' +
   date.toLocaleTimeString();

  var reversed = "";
  for (var i = message.length - 1; i >= 0; i--) {
   reversed += message[i];
  }
   ws.send(reversed);
  });

 var date = new Date();
 var str = date.toLocaleDateString() + ' ' +
  date.toLocaleTimeString();
 ws.send('WebSocket connected at: ' + str);
});

sobota, 27 października 2012

[HTML|JS|CSS] HTML5: Offline Web Applications

Najprościej mówiąc aplikacje offline, to takie, które będą działały po utracie połączenia internetowego. Aby było to możliwe, cały dokument html wraz ze wszystkimi zależnościami musi być przechowywany na komputerze użytkownika i dodatkowo potrzebujemy mechanizmów powiadających o utracie (lub odzyskaniu) połączenia. Oczywiście nie jesteśmy w stanie przesłać wszystkiego, ale pewna ilość plików wystarczy, aby zachować funkcjonalność w trybie offline.

Do tej pory przeglądarki udostępniały tzw. Browser Cache. Jego zasada działania jest następująca : przy odwiedzeniu pewnej strony po raz pierwszy, tworzony jest dla niej folder z cache,  z pobranymi plikami (html, js, css, img). Przy kolejnych requestach o ten plik pobierany jest on z cache (jeżeli w międzyczasie nie został zmieniony), przez co czas od wysłania żądania do wyświetlenia całej zawartości strony jest znacznie krótszy. Gdy utracone zostaje połączenie, z cache pobrany zostanie tylko dokument html, bez plików js, css i plików graficznych.

Nowa funkcjonalność to Application Cache, który również jest miejscem na komputerze użytkownika, z którego strony mogą być dostarczane. Różnica polega na tym, że pliki nie są pobierane pojedynczo, a "tranzakcyjnie". Oznacza to mniej więcej tyle, że nie będziemy mogli otworzyć strony, jeżeli którykolwiek z plików nie został pobrany. Z drugiej strony, jeżeli transakcja zostanie zakończona pomyślnie, to mamy pewność, że cała zawartość strony znajduje się na naszym dysku.  

Skąd przeglądarka ma wiedzieć o tym, które pliki tworzą razem aplikację ? Mówi o tym plik manifestu, o którego strukturze nieco więcej zostanie napisane poniżej. Warto pamiętać, że zmiana dowolnego pliku aplikacji na serwerze nie spowoduje jego aktualizacji po stronie klienta. Dzieje się tak dlatego, że pliki aktualizowane są dopiero przy zmianie manifestu.

Aby móc skorzystać z funkcjonalności aplikacji offline, nie wolno korzystać z browser cache, a także należy pliki manifestu przesyłać ze specjalnym Content-Type w nagłówku. Przykładowa konfiguracja serwera w Node.js poniżej.

var express = require('express');
var http = require('http');
var app = express();

app.use(express.static(__dirname));

app.get("/cache.manifest", function(req, res){
  res.header("Content-Type", "text/cache-manifest");
  res.end("CACHE MANIFEST");
});

app.listen('1027');

Manifest

Dołącza się go w znaczniku html, może być plikiem o dowolnym rozszerzeniu, np:
<html manifest="cache.manifest">
Przykładowy plik manifestu:

CACHE MANIFEST
# version 1.2

CACHE:
script.js
HTML5_Logo.png
http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.2/jquery.min.js


NETWORK:
jquery.jpg

Mamy dostępne kilka sekcji. Wersja może być przydatna, ponieważ zmiana wersji spowoduje pobranie na nowo plików przez przeglądarkę.  
CACHE - lista plików do pobrania
NETWORK - pliki, które z jakiegoś powodu muszą być pobierane zawsze
FALLBACK - zamienniki dla plików, których nie da się pobrać gdy aplikacja przejdzie w tryb offline.

W javascripcie poprzez obiekt applicationCache, możemy obsłużyć zdarzenia, jakie występują w przypadku update'u manifestu oraz pobierania plików z Application Cache.

Pełny kod z przykładem obsługi wszystkich dostępnych zdarzeń poniżej:


<!doctype html>
<html manifest="cache.manifest">
<head>
<meta charset="utf-8">
<title>Offline Web Applications</title>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript">
 $(function(){
 window.applicationCache.onupdateready = function(e){
  console.log('onupdateready');
  applicationCache.swapCache();
 }
});
</script>
</head>
<body>
 <h1>hello world</h1>
</body>
</html>



$(function(){
 if(window.applicationCache){
  console.log('supporting app cache');

  window.applicationCache.onchecking = function(e){
   console.log('onchecking');
  }

  window.applicationCache.oncached = function(e){
   console.log('oncached');
  }

  window.applicationCache.onupdate = function(e){
   console.log('onupdate');
  }

  window.applicationCache.onobsolete = function(e){
   console.log('onobsolete');
  }

  window.applicationCache.ondownloading = function(e){
   console.log('ondownloading');
  }
 }
});

czwartek, 11 października 2012

[HTML|JS|CSS] Node.js: RESTful API

Aby serwer mógł komunikować się ze stroną, możemy w prosty sposób wystawić RESTowe API dostosowane do naszych potrzeb. Z użyciem Node.js oraz expressa staje się to bardzo proste. Mamy do dyspozycji cztery metody:
  • GET
  • POST
  • PUT
  • DELETE
Poniżej przykład, jak zaprojektować takie API po stronie serwerowej. Użyto w nim dwóch obiektów middleware. Obiekt express.bodyParser, jak nazwa wskazuje parsuje body requestów typu post na obiekt javascript, dzięki czemu można odwoływać się do poszczególnych propercji takiego obiektu. Użycie express.static konfiguruje ścieżkę do szablonu html względem pliku serwera.

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

app.use(express.bodyParser());
app.use(express.static(__dirname + '/www'));

Samo API można zaprojektować w taki sposób jak poniżej.

app.get('/store/:key', function(req, resp) {
 var val = store[req.params.key];
 if(val){
  resp.send(val);
 }
 else{
  resp.send('undefined',400);
 }
});

app.post('/store/', function(req, resp) {
 store[req.body.key] = req.body.value;
    resp.send('OK');
});

app.put('/store/', function(req, resp){
 store[req.body.key] = req.body.value;
    resp.send('OK');
});

app.del('/store/:key', function(req, resp) {
 var val = store[req.params.key];
 console.log(req.params.key);
 if(val){
  store[req.params.key] = undefined;
  resp.send("OK");
 }
 else{
  resp.send('undefined',400);
 }
});

środa, 10 października 2012

[HTML|JS|CSS] Node.js: Operacje na plikach

Jeżeli chcemy korzystając z Node.js przeprowadzać operacje na plikach, mamy do dyspozycji moduł fs. Obszerne API powinno wystarczyć na potrzeby większości serwerów. Do odczytu i zapisu służą odpowiednio funkcje fs.readFile oraz fs.writeFile. Przy odczycie poza nazwą pliku podaje się kodowanie oraz funkcję jako callback, w którym dostępne są odczytane dane. Przy zapisie wystarczy podać nazwę oraz dane do zapisu. Przykład użycia poniżej.

var http = require("http");
var fs = require("fs");

http.createServer(function (request, response) {
 request.on("end", function () {
  if (request.url == '/') {
   fs.readFile("samplefiles/lyrics.txt",
    'utf-8', function (error, data) {
    response.writeHead(200, {
     'Content-Type': 'text/plain'
    });
    response.end(data);
    fs.readFile("samplefiles/stats.txt", 'utf-8', 
     function(error, data){
      var content = data + '\r\n';
      content += (new Date()).toString();
      fs.writeFile("samplefiles/stats.txt",
       content);
    })
   });
  }
  else
  {
   console.log('favicon request');
  }
 });
}).listen(8080);

[HTML|JS|CSS] Node.js: Wprowadzenie

Node.js jest bardzo modnym ostatnio środowiskiem pozwalającym na tworzenie aplikacji internetowych, przeważnie web serwerów.  Aplikacje te pisane są w JavaScripcie, z całym zestawem jego wad i zalet, na pewno jednak wyróżnia je duża skalowalność, o czym można przeczytać wszędzie gdzie pisze się coś na temat Node'a. Przy projektowaniu środowiska zastosowano event - driven programming - podejście w którym wykonywanie programu determinowane jest przez zdarzenia i odpowiadające im callbacki. Zatem każda funkcja w Node.js jest asynchroniczna.

Aby uprościć architekturę wprowadza się pojęcie modułów. Są to wydzielone, logiczne fragmenty kodu, które możemy importować do Node'a za pomocą instrukcji require(nazwa modułu). Domyślnie Node.js szuka modułu w folderze o nazwie node_modules. Możemy także podać ścieżkę do naszego modułu, rozpoczynającą się od ./, np. require('./mymodules/module').

Aby zainstalować środowisko należy pobrać z tej strony instalator dla naszego systemu operacyjnego. Wraz z serwerem zainstalowany zostanie npm, manager pakietów podobny np. do ruby gems. Poleceniem

npm install <nazwa_pakietu>

możemy pobrać dowolny pakiet.

Do uruchamiania aplikacji napisanych w node warto pobrać pakiet supervisor, który należy zainstalować globalnie.

npm install supervisor -g

Po napisaniu naszej aplikacji, np w pliku mojaaplikacja.js możemy uruchamiać ją za pomocą supervisora poleceniem

supervisor mojaaplikacja.js

Dzięki temu każda zmiana w pliku mojaaplikacja.js spowoduje restart serwera.

Kolejnym pakietem, który warto zainstalować jest express, który zainstalować należy w folderze z naszym projektem.

npm install express

Jest to pakiet, pozwalający w łatwy sposób tworzyć aplikacje internetowe.

Poniżej przykład użycia własnego modułu wraz z pierwszą aplikacją z użyciem expressa.
Plik mymodule.js

var name = "Michael";

var obj = {
 speak : function(){
  console.log("My name is " + name);
 }
}

console.log('Processing module during require directive');
module.exports = exports = obj;

Plik serwera

var express = require('express');
var mymodule = require('./mymodules/mymodule.js')
var app = express();

app.get('/', function(req, res){
 mymodule.speak();
   res.send('Hello World');
});

app.listen(8080);