Skip to content

Фреймворки в Node.js: fab

09/04/2010

Fab — микрофреймворк, вдохновлённый элегантностью и простотой использования jQuery. Он довольно активно развивается, сейчас доступна третья версия (автор практически переписал фреймворк).

Установка

Качаем архив:

  wget -r http://github.com/jed/fab/tarball/master
  

Это фреймворк ветки master. Если Вам нужна последняя версия (например, попробовать написать плагин), Вам понадобится ветка v3:

  wget -r http://github.com/jed/fab/tarball/v3
  

Распаковываем полученный архив. В архиве есть make-файл, но сам фреймворк не требует сборки — файл используется для запуска тестов.

Использование

Fab можно использовать двумя способами — запуская с его помощью скрипты или подключая фреймворк как модуль. Попробуем оба способа по очереди, чтобы увидеть разницу.

Вначале создаём простейшее fab-приложение:

  (fab)(fab)
  

Да, и всё. Это приложение поднимет HTTP-сервер, и будет отвечать статусом 404 на любой запрос (мы не указали ни одного пути).

Запускается этот файл так:

  node lib/node.js fab/examples/hello.js -p 8000
  

Здесь lib/node.js это путь к файлу в фреймворке fab. Здесь я предполагаю что мы находимся в папке фреймворка.

Но видеть 404 Not Found на сайте не очень интересно. Попробуем расширить наш пример и задать пути:

(fab)
  ('/', 'The Emperor protects!')
  ('/hello', 'Hello world')
(fab)
  

Запускаем. Теперь по адресу / мы видим текст «The Emperor protects!», а по адресу /hello — традиционное Hello world..

То же самое с явным подключением фреймворка будет выглядеть так:

var fab = require("../fab");
var http = require("http");

http.createServer(

    (fab)
      ('/', 'The Emperor protects!')
      ('/hello', 'Hello world')
    (fab)

).listen( 8000 );

И запускаться такой скрипт будет традиционным способом: node simple.js.

Сам автор сравнивает fab с jQuery — и действительно, синтаксис очень похож. Тот же принцип «найти путь и навесить обработчик» («fab» изначально обозначало «Finding and binding«). В качестве аргументов пути могут использоваться и функции:

( fab )
  ( "/time", function() {
    return "the time is " + (new Date).toTimeString();
  })
  ( "/date", function() {
    return "the date is " + (new Date).toDateString();
  })
( fab )

Также пути можно вкладывать друг в друга:

( fab )
  ( "/hello" )
    [ "GET" ]( "hello, world!" )
    ( "/earth", "hello, Earth!" )
    ( "/mars", "hello, Mars!" )
  ()
( fab )

Здесь на странице /hello будет «hello, world!», на /hello/earth — «Hello, Earth!» и на /hello/mars — «hello, Mars!».

То же самое можно сделать, используя пути с регулярными выражениями:

( fab )
  ( "/hello" )
    [ "GET" ]( "hello, world!" )
    ( /\/(\w+)/, function() {
        return "hello, " + this.url.capture[ 0 ] + "!"
    })
  ()
( fab )

Теперь на /hello/jupiter можно наблюдать «hello, jupiter!».

Также можно обрабатывать статусы прямо в путях. Например, если путь не совпадает с регулярным выражением или не задан, можно отдавать пользовательскую 404 страницу:

( fab )
  ( "/hello" )
    [ "GET" ]( "hello!" )
    ( /\/([a-z]+)/, function(){
      return "hello, " + this.url.capture[ 0 ] + "!"
    })
    [ 404 ]( "sorry, only lowercase names are supported." )
  ()
  [ 404 ]( "sorry, only /hello paths are valid." )
( fab )

Также можно отдавать контент асинхронно:

( fab )
  ( "/hello", function( respond ) {
    setTimeout( function() {
      respond( "hello, sorry to make you wait!", null );
    }, 2000 );
  })
( fab )

Можно вешать обработчики на multipart-запросы, приходящие по частям:

( fab )
  ( "/hello" )
    [ "POST" ]( function( respond ) {
      var buffer = "";
      return function( data ) {
        if ( data !== null ) buffer += data;
        else respond( buffer.length + " characters sent", null );
      }
    })
  ()
( fab )

Архитектура и расширяемость

Первая версия фреймворка была просто роутером с необычным синтаксисом. Вызовы возвращаемых функций для JavaScript выглядят не очень привычно, но по сути не сильно отличаются например от цепных методов jQuery. К третьей версии у fab появилась своя необычная архитектура. Сам фреймворк не предоставляет объектов, методов, не сохраняет состояния — он служит связующим звеном многих других микроприложений. Роутер — только одно из них. Кроме него fab включает приложения для работы с потоковыми данными, работы с файловой системой, шаблонизатор, модуль регулярных выражений и т.п.

Внутренние приложения в fab делятся на три типа: унарные, бинарные и тернарные.

Унарные приложения

Унарное приложение общается только с одним приложением. Например:

function hello( respond ) {
  respond({ body: "hello world." })();
}

Это как раз то, что в других JavaScript-фреймворках называется «обработчиком». В таком варианте функция ничего не знает о запросе, и может возвращать только статический ответ. Чтобы ответ мог получить доступ к данным запроса, надо вернуть функцию:

function hello( respond ) {
  return function( req ) {
    respond({ body: "you are requesting " + req.url + "." })();
  }
}

Теперь приложение можно использовать в цепочке вызовов, вызывая возвращаемую функцию:

require( "fab" )

()
  (hello)('world')
()

Бинарные приложения

Бинарное приложение может общаться с двумя приложениями, одно выше в иерархии вызовов, второе ниже.

function notify( downstream, upstream ) {
  require( "sys" ).puts( "binary app called!" )
  return downstream( upstream );
}

В этом примере notify — бинарное приложение, пишущее данные в лог и просто передающее данные из нижестоящего приложения вышестоящему.

Бинарные приложения используются для изменения данных и передачи их дальше — например, добавления заголовков к HTTP-ответу.

Тернарные приложения

Тернарные приложения интереснее — они действуют как посредники между тремя другими приложениями, одно из которых выше в иерархии вызовов, а два других — ниже.

function isGET( hit, miss, respond ) {
  return function( req ) {
    return ( req.method === "GET" ? hit : miss )( respond )( req );
  }
}

Это приложение вызовет функцию hit если метод совпадает с GET, и функцию miss в любом другом случае. Именно на таких приложениях построен роутинг и другие условные вещи.

(fab)
    (isget)("method is get")("method is not get")
(fab)

Все встреченные строки, кстати, будут автоматически преобразованы в приложения, возвращающие соответствующую строку. Несколько условий в цепочке позволяют создавать подобие case — конструкции, именно для этого последним вызовом передаётся пустой: ().

(fab)

    (isget)("method is get")(ispost)("method is post")()
(fab)

То же самое, записанное в более удобном виде, выглядит как уже использованный нами роутер:

(fab)
    (isget)
        ("method is get")
    (ispost)
        ("method is post")
    ()
(fab)

Заключение

Fab — фреймворк с интересной архитектурой и огромным потенциалом. Как роутер он работает отлично, позволяя создавать простые сайты с очень чистым и понятным синтаксисом. Fab легко расширяем, так что недостающие возможности (вроде поддержки сессий) можно добавить самостоятельно. Автор надеется что вокруг фреймворка со временем вырастет такая же экосистема плагинов как у jQuery.

Фреймворки в Node.js

Ссылки по теме

P.S. Уже после публикации со мной связался автор фреймворка и попросил подождать с обзором до следующей недели, когда будет готова новая версия. Я сделаю апдейт, как только это произойдёт.

Добавить комментарий

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: