Статьи

Работа с данными в Sails.js

Sails.js — это новая платформа Node.js, ориентированная на свободу и умные настройки по умолчанию. В этой статье мы рассмотрим некоторые функции данных, которые Sails предоставляет «из коробки» для простого создания сложных приложений.


Лучше всего выбрать паруса, создатель Sails, Майк Макнил , «Паруса были созданы по необходимости». Многие фреймворки, которые вы видите вокруг, созданы почти для академической стороны, эти фреймворки обычно поощряют лучшие практики и создают платформу для разработчиков, чтобы создавать вещи быстрее или лучше.

Sails, с другой стороны, был создан для производства, он не пытается дать вам новый синтаксис или платформу, это прочная основа, предназначенная для быстрого создания «работы клиента». Контраст может быть тонким, но есть несколько четких различий.

Чтобы проиллюстрировать, о чем я говорю, давайте взглянем на Метеор . Meteor, вероятно, сегодня является ведущей платформой JS, но это яркий пример фреймворка, ради фреймворка. Теперь это не плохо, я большой сторонник Meteor, я имею в виду, что они намеревались создать фреймворк и хорошо поработали над ним, а Майк, с другой стороны, решил ускорить работу клиента. , Паруса это просто средство для достижения цели.

В Meteor практически все абстрагировано, и вы используете JavaScript и Meteor API для кодирования всего. Принимая во внимание, что Паруса не предназначены, чтобы быть новой платформой, таким образом ничто не скрыто.

Он опирается на Socket.io и популярную платформу Express, и у вас есть доступ к ним полностью, изначально. Вы начинаете видеть разницу?

Кроме того, поскольку Sails ориентирован на производство в первую очередь, он построен с несколькими вариантами масштабирования и безопасности.

Есть много о чем поговорить, но в этой статье я хотел бы сосредоточиться на том, как Sails обрабатывает данные, и как вы можете использовать некоторые из более продвинутых функций Sails для выполнения действительно крутых действий.


На тот случай, если у вас еще не установлены паруса, вы можете сделать это через NPM , выполнив:

1
sudo npm install -g sails

Теперь давайте немного поговорим о Socket.io и Express, прежде чем мы перейдем в Sails. Эндрю Берджесс (Andrew Burgess) предлагает вам серию отличных премиум-статей о Express , но я ознакомлю вас с основами обеих этих библиотек:

Socket.io — это библиотека pub / sub, которая запускается как на сервере, так и на клиенте, и позволяет им общаться через веб-сокеты.

Краткий пример может выглядеть примерно так:

Этот код начинается с socket.io библиотеки socket.io , прослушивания соединения, а затем, когда подключается другой сокет, он отправляет ему сообщение, адресованное событию welcomeMessage , и, наконец, передает некоторый JSON.

Далее на клиенте вы бы написали что-то вроде:

Здесь мы подключаемся к серверу и прослушиваем только что welcomeMessage событие welcomeMessage . Как вы можете видеть, это довольно простой сервер публикации / подписки, который является двунаправленным (клиент может отправлять сообщения и для сервера).

Теперь давайте посмотрим на Экспресс:

Простейшей формой экспресс-маршрута может быть что-то вроде:

Это определяет простой маршрут, так что, когда пользователь переходит на адрес вашего сайта и пытается получить доступ к странице /users , ему будет показано сообщение "Hello from '/users' !" ,

Так что Express — это платформа для обработки HTTP-запросов, а Socket.io — библиотека веб-сокетов. Однако команда Sails сделала внутреннее сопоставление всех маршрутов Express с Socket.io. Это означает, что вы можете вызывать любой из HTTP-маршрутов через веб-сокеты.

Теперь это довольно круто! Но до сих пор не хватает одного фрагмента головоломки — это Sails Blueprints.

Sails позволяет генерировать модели так же, как и в других средах. Разница в том, что Sails также может генерировать готовый к работе API RESTfull для их использования. Это означает, что если вы сгенерируете модель с именем ‘ users ‘, вы можете сразу же выполнить запросы RESTfull на ресурсе /users без необходимости какого-либо кодирования.

Если вы новичок в API RESTful, это просто способ доступа к данным, где операции CRUD отображаются на различные методы HTTP.

Таким образом, запрос GET для « /users » получит всех пользователей, запрос POST создаст нового пользователя и т. Д.

Так что же все это значит?

Это означает, что у нас есть полный RESTfull API, сопоставленный с Socket.io через Sails, без написания ни одной строки кода!

Но почему сокеты лучше извлекают данные, чем Ajax-запрос? Ну, помимо того, что протокол является более узким, сокеты остаются открытыми для двунаправленной связи, и Sails воспользовалась этим. Sails не только передаст вам данные, но и автоматически подпишет вас на обновления в этой базе данных, и каждый раз, когда что-то будет добавлено, удалено или обновлено, ваш клиент получит уведомление через веб-сокет, сообщающее вам об этом.

Вот почему Sails так классно!


Следующая тема, которую я хотел бы затронуть, — интеграция с Backbone, потому что, если вы не используете инфраструктуру JavaScript, вы делаете это неправильно.

Учитывая это, Sails и Backbone являются идеальной парой. Магистраль, как и Sails, крайне ненавязчива, все ее функции доступны, могут быть переопределены и необязательны.

Если вы использовали Backbone до этого, вы можете знать, что он изначально соединяется с REST API, поэтому сразу после установки вы можете синхронизировать данные на внешнем интерфейсе с вашим приложением Sails.

Но хватит разговоров, давайте посмотрим на все это в действии, создав базовое приложение для чата. Для начала откройте окно терминала и введите:

1
2
3
4
5
6
sails new ChatApp
cd ChatApp
sails generate model users
sails generate model messages
sails generate controller messages
sails generate controller main

Это создаст новое приложение и сгенерирует некоторые файлы для нас. Вы можете видеть сверху, есть два разных ресурса, которые вы можете генерировать; модели и контроллеры. Если вы знакомы с шаблоном проектирования MVC, то вы должны знать, что это такое, но вкратце, модели — это ваши данные, а контроллеры содержат ваш логический код. Таким образом, нам понадобятся две коллекции, одна для хранения пользователей и одна для сообщений.

Далее, для контроллеров нам нужен один для обработки маршрутов страниц, я назвал его « main », затем у нас есть второй контроллер с именем « messages ». Теперь вы можете спросить, почему я создал контроллер с тем же именем, что и модель наших messages ? Ну, если вы помните, я сказал, что Sails может создать REST API для вас. В результате при создании пустого контроллера с тем же именем, что и у модели, Sails будет вынужден отступить и создать REST API для соответствующего ресурса.

Итак, мы создали контроллер для нашей модели messages , но нет необходимости создавать контроллер для модели пользователей, поэтому я просто не учел его. И это все, что нужно для создания моделей и контроллеров.

Далее давайте настроим несколько маршрутов.

Маршруты всегда безопасны для начала, потому что у вас обычно есть четкое представление о том, какие страницы будут создаваться.

Итак, откройте файл routes.js который находится в папке config , на первый взгляд он может показаться немного перегруженным, но если вы удалите все комментарии и добавите следующие маршруты, у вас останется что-то вроде этого:

У нас есть домашняя страница, страница чата, а затем две страницы для обработки страниц входа и регистрации. Я поместил их все в один контроллер, но в Sails вы можете создать столько контроллеров, сколько захотите.

Далее, давайте посмотрим на модель сгенерированных messages которая может быть расположена в « api > models > Messages.js ». Нам нужно добавить необходимые столбцы в нашу модель. Теперь это не является абсолютно необходимым, но оно создаст для нас некоторые вспомогательные функции, которые мы можем использовать:

Для модели messages мы начинаем с id пользователя, которому принадлежит это сообщение, username поэтому нам не нужно запрашивать это отдельно, а затем фактического message .

Теперь давайте заполним модель пользователя:

И это все, у нас есть только атрибуты имени username и password . Следующим шагом является создание наших функций маршрута внутри MainController .

Так что откройте MainController , который можно найти в « api > controllers > MainController.js ». Давайте начнем с создания функции для каждого из маршрутов, которые мы определили выше:

Если вы знакомы с Express, вы будете рады видеть, что эти функции являются стандартными функциями маршрутизации Express. Они получают две переменные: req для HTTP-запроса и res для создания ответа.

Следуя шаблону MVC, Sails предлагает функцию рендеринга видов. Домашняя страница не требует ничего особенного, поэтому давайте просто представим представление.

Паруса склоняются больше к соглашению по конфигурации, поэтому, когда вы вызываете res.view(); Паруса будут искать файл представления (с расширением .ejs по умолчанию), используя следующий шаблон: ‘ views > controllerName > methodName.ejs ‘. Поэтому для этого вызова он будет искать « views > main > index.ejs ». Также стоит отметить, что эти представления содержат только определенные части страницы. Если вы посмотрите на ‘ views > layout.ejs ‘, вы увидите в середине вызов для <%- body %> , именно здесь будет вставлен ваш файл представления. По умолчанию он использует этот файл layout.ejs , но вы можете использовать другие файлы макета, просто передав имя макета в res.view() под свойством с именем layout. Например: ‘ res.view( { layout: "other.ejs" } ); ».

Я собираюсь использовать файл макета по умолчанию с небольшой настройкой, я собираюсь добавить jQuery, Backbone и Underscore. Так что в файле ‘ layout.ejs ‘ перед закрывающим </head> добавьте следующие строки:

Теперь мы готовы создать домашнюю страницу.

Давайте создадим новую папку внутри папки views именем main , а внутри нашей новой main папки мы создадим новый файл с именем index.ejs.

Внутри файла давайте просто создадим форму для входа и регистрации:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<h1>Code Chat</h1>
<div>
    <h3>Login</h3>
    <input type=»text» id=»loginName» placeholder=»name» />
    <input type=»password» id=»loginPassword» placeholder=»password» />
    <button id=»loginButton»>Login</button>
</div>
<div>
    <h3>Signup</h3>
    <input type=»text» id=»signupName» placeholder=»name» />
    <input type=»password» id=»signupPassword» placeholder=»password» />
    <input type=»password» id=»signupConfirmPassword» placeholder=»confirm password» />
    <button id=»signupButton»>Signup</button>
</div>

Довольно просто, просто самое необходимое.

Затем нам нужно добавить немного JS для связи с сервером. Теперь это не будет зависеть от Sails, мы просто отправим запрос AJAX через jQuery на сервер Sails.

Этот код может быть включен на самой странице или загружен через отдельный файл JS. Для удобства я просто помещу его внизу той же страницы:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<script>
    $(«#loginButton»).click(function(){
        var username = $(«#loginName»).val();
        var password = $(«#loginPassword»).val();
        if (username && password) {
            $.post(
                ‘/login’,
                {username: username, password:password},
                function () {
                    window.location = «/chat»;
                }
            ).fail(function(res){
                alert(«Error: » + res.getResponseHeader(«error»));
            });
        } else {
            alert(«A username and password is required»);
        }
    });
</script>

Это все просто стандартные JS и jQuery, мы слушаем событие click на кнопке входа в систему, проверяем, заполнены ли поля имени пользователя и пароля, и публикуем данные в маршрут ‘ /login ‘. Если вход выполнен успешно, мы перенаправляем пользователя на страницу чата, в противном случае мы отобразим ошибку, возвращенную сервером.

Далее, давайте создадим то же самое для области регистрации:

Этот код почти идентичен, настолько, что вы, вероятно, можете просто абстрагировать всю Ajax-часть в свою собственную функцию, но для этого урока это хорошо.

Теперь нам нужно вернуться к нашему ‘ MainController ‘ и обработать эти два маршрута, но прежде чем мы это сделаем, я хочу установить модуль Node. Нам нужно будет хэшировать пароль, так как обычные текстовые пароли не очень хорошая вещь, даже для демонстрации! Я нашел хороший модуль Дэвида Вуда под названием «хэш пароля» , который отлично сработает.

Чтобы установить его, просто перейдите в корень приложения Sails из терминала и введите: npm install password-hash .

После установки давайте откроем MainController и реализуем два необходимых маршрута. Начнем с signup :

Это немного многословно, но все, что мы здесь делаем, это читаем имя пользователя и пароль из запроса POST и проверяем, что имя пользователя еще не занято. Вы можете видеть, что я также использую хэш-пароль, который мы только что установили, его очень просто использовать, просто передайте пароль в метод generate, и он будет хэшировать его, используя случайную соль.

Также стоит упомянуть, что в каждом возможном месте, где мы можем столкнуться с ошибкой или проблемой, мы отправляем обратно код ошибки HTTP и возвращаем сообщение через специальный заголовок с именем « error », который, если вы помните, мы отображение в сообщении предупреждения на странице индекса.

Другим примечательным моментом является тот факт, что мы используем «волшебную» функцию с именем « findByUsername », это стало возможным, потому что у нас есть столбец username внутри нашей модели Users.

Наконец, внизу вы можете увидеть, все ли прошло хорошо, мы сохраняем пользователя в переменной сеанса и возвращаем его с кодом состояния по умолчанию, равным 200, который сообщит jQuery, что запрос AJAX был успешным.

Далее давайте напишем функцию входа в систему:

Опять же, это очень похоже на предыдущую функцию signup , мы ищем пользователя с тем же именем пользователя, которое было опубликовано в форме, и, если оно найдет его, мы проверяем, совпадает ли пароль, используя метод verify хешера. Причина, по которой мы не можем просто снова хэшировать пароль и передавать его в функцию find моделей, заключается в том, что хеш-код использует случайную соль, поэтому если мы снова хешируем пароль, он будет равен чему-то другому.

Остальной код такой же; если все получилось, мы сохраняем пользователя в сеансе и возвращаем его, в противном случае мы отправляем обратно сообщение об ошибке.

Система входа в систему завершена, и мы наконец-то можем перейти к созданию функции чата.

Поскольку мы будем использовать Backbone для получения сообщений, фактическая функция маршрута будет очень простой. Вот полная функция чата:

Мы начнем с проверки, вошел ли пользователь в систему или нет, если это произойдет, то он загрузит представление, передав ему имя пользователя, которое было в сеансе, в противном случае мы просто перенаправляем на домашнюю страницу.

Теперь давайте создадим новый вид с именем chat.ejs внутри main папки. Откройте его и давайте создадим простую форму для размещения новых сообщений и контейнер div для отображения всех из них.

1
2
3
4
5
6
7
<h2>Welcome <%= username %></h2>
<div id=»newMessageForm»>
    <textarea id=»message» placeholder=»Enter your message here:»></textarea>
    <button id=»postMessageButton»>Add Message</button>
</div>
<div id=»messagesContainer»>
</div>

Так что для этого представления мы просто использовали довольно стандартный HTML. Единственное, что может потребовать некоторого объяснения, это код <%= username %> , этот стиль кодирования не специфичен для Sails, это фактически синтаксис для EJS. Этот синтаксис очень похож на короткие теги PHP. <% эквивалентно <? в PHP и <%= совпадает с <?= . Первый фрагмент EJS позволяет вам интегрировать стандартный код JS на страницу, тогда как второй выводит код внутри. Здесь мы просто распечатываем имя пользователя, которое мы передали из контроллера.

Остальная часть нашего чата будет вся JavaScript. Для начала давайте посмотрим, как можно написать функциональность чата с использованием стандартной Backbone, а затем мы увидим, как использовать преимущества веб-сокетов.

Внизу страницы добавьте следующий JS:

Так как Sails автоматически создает API, который Backbone понимает изначально, не нужно писать никакого дополнительного серверного кода, это не намного легче, чем это. Это то, о чем я говорил, когда говорил, что Sails не был создан как «каркас». Он не пытается заставить вас использовать свой собственный синтаксис, он был сделан, чтобы добиться цели, и, как вы можете видеть, он обеспечивает.

Чтобы проверить это, откройте окно терминала и перейдите в папку приложения Sails, затем введите « sails lift », чтобы запустить его. По умолчанию он запускается по http://localhost:1337 . Теперь просто зарегистрируйтесь и опубликуйте несколько сообщений.

Чтобы увидеть ваши опубликованные сообщения, вы можете console.log переменную messages или посмотреть на нее внутри консоли браузера. Теперь следующая вещь, которую мы должны реализовать, это представление, чтобы мы могли видеть опубликованные сообщения в браузере.

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

Вверху вы можете видеть, что мне пришлось изменить настройки Underscore по умолчанию с использования синтаксиса EJS внутри шаблонов, чтобы вместо этого использовать синтаксис Mustache. Это потому, что страница уже является документом EJS, поэтому она будет обрабатываться на сервере, а не в Underscore.

Примечание : я не придумал Regex для этого, этот кредит идет на сами документы Underscore .

Наконец, внизу вы можете видеть, что мы создали новый экземпляр этого представления, передав ему переменную коллекции.

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


Теперь вы, возможно, заметили, что мы не устанавливаем userId или username при отправке сообщений, и это делается в целях безопасности.

Вы не хотите устанавливать такой контроль на стороне клиента. Если все, что кому-то нужно, это изменить переменную JavaScript для управления учетной записью другого пользователя, у вас возникнет серьезная проблема.

Итак, как вы должны справиться с этим? Ну с политикой конечно.

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

Для этого приложения давайте создадим политику для наших сообщений. Политики применяются к контроллерам, поэтому их можно запускать даже на обычных страницах, но для этого учебного руководства давайте просто придерживаться одного для наших messages Model.

Создайте файл с именем «MessagesPolicy.js» в папке « api > policies » и введите следующее:

Итак, что здесь происходит? Вы можете видеть, что эта функция похожа на обычную функцию маршрутизации, но разница заключается в третьем параметре, который будет вызывать следующее промежуточное ПО в стеке. Если вы новичок в идее промежуточного программного обеспечения, вы можете думать о нем как о русской матрешке. Каждый уровень получает запрос вместе с переменными ответа, и они могут изменять их по своему усмотрению. Если они отвечают всем требованиям, слой может передать его дальше, пока не достигнет центра, который является функцией маршрута.

Итак, мы проверяем, вошел ли пользователь в систему, если нет, мы показываем ошибку 403, и запрос заканчивается здесь. В противном случае (т.е. пользователь вошел в систему) мы вызываем next(); передать это. В середине приведенного выше кода, где мы вводим некоторые переменные post. Мы применяем это ко всем вызовам на контроллере ‘messages’ (в основном API), поэтому мы получаем действие и проверяем, пытается ли этот запрос создать новое сообщение, и в этом случае мы добавляем поля сообщения для id пользователя. и username .

Затем откройте файл policy.js, который находится в папке config, и добавьте политику, которую мы только что создали. Итак, ваш файл должен выглядеть так:

После этого нам нужно будет удалить все старые записи, так как они не содержат этих новых фрагментов информации. Итак, закройте сервер Sails (ctrl-c) и в том же окне терминала введите: rm -r .tmp чтобы удалить временную базу данных, что дает нам чистую доску.

Далее, давайте добавим имя пользователя к реальным сообщениям, поэтому в ‘chat.ejs’ измените шаблон на:

Перезапустите сервер Sails (снова используя sails lift ) и зарегистрируйте другого нового пользователя, чтобы протестировать его. Если все работает правильно, вы сможете добавлять сообщения и видеть свое имя в посте.

На данный момент у нас есть довольно хорошая настройка, мы автоматически извлекаем сообщение, используя Backbone и API, плюс у нас есть некоторые базовые меры безопасности. Проблема в том, что он не будет обновляться, когда другие люди публикуют сообщения. Теперь вы можете решить эту проблему путем создания интервала JavaScript и опроса обновлений, но мы можем добиться большего.

Ранее я упоминал, что Sails использует двунаправленные возможности websockets для публикации обновлений подписанных данных. Используя эти обновления, мы можем прослушивать новые дополнения к таблице сообщений и соответственно обновлять коллекцию.

Итак, в файле chat.ejs давайте создадим новый вид коллекции; SailsCollection:

Теперь это может быть долго, но на самом деле это очень просто, давайте пройдемся по нему. Мы начнем с добавления двух новых свойств в объект Collection, одно из которых содержит имя модели Sails, а другое — веб-сокет. Затем мы sync функцию sync , если вы знакомы с Backbone, то вы будете знать, что это функция, которая взаимодействует с сервером при вызове таких вещей, как fetch . Обычно он запускает запросы Ajax, но мы собираемся настроить его для сокетной связи.

Теперь мы не используем большую часть функциональности, которую предлагает функция sync , в основном потому, что мы не добавили пользователям возможность обновлять или удалять сообщения, а просто для полноты я включу их в определение функции.

Давайте посмотрим на первую часть функции sync :

Этот код сначала проверяет, были ли отправлены какие-либо предложения ‘ where ‘, это позволит вам делать такие вещи: messages.fetch({ where : { id: 4 } }); выбирать только те строки, где идентификатор равен четырем.

После этого у нас есть некоторый код, который гарантирует, что свойство ‘ sailsCollection ‘ установлено, в противном случае мы регистрируем сообщение об ошибке. После этого мы создаем новый сокет и подключаемся к серверу, прослушивая соединение с событием on('connect') .

После подключения мы запрашиваем индекс sailsCollection , указанный в текущем списке моделей. Когда он получает данные, мы используем функцию set для первоначальной установки моделей.

Хорошо, теперь у нас есть эквивалент стандартной команды fetch . Следующий блок кода, где происходят push-уведомления:

Теперь выполняемое действие (независимо от того, создаем ли мы, обновляем или удаляем сообщение) можно найти внутри фактического msg , которое затем находится внутри uri . Чтобы получить действие, мы разделяем URI на прямую косую черту (‘/’) и берем только последний сегмент, используя функцию pop . Затем мы пытаемся сопоставить его с тремя возможными действиями create , update или destroy .

Остальное стандартное Backbone, мы либо добавляем, редактируем, либо удаляем указанную модель. После того, как наш новый класс почти завершен, остается только изменить текущую MessageCollection . Вместо того, чтобы расширять коллекцию Backbone, она должна расширять нашу новую коллекцию, например:

В дополнение к расширению нашей новой коллекции мы внесем еще одно изменение, чтобы вместо установки свойства URL мы теперь установили свойство sailsCollection. И это все, что нужно сделать. Откройте приложение в двух разных браузерах (например, Chrome и Safari) и зарегистрируйте двух отдельных пользователей. Вы должны увидеть, что отправленные сообщения из одного из браузеров немедленно отображаются в другом, без опроса и без проблем.

Скриншот чата

Паруса — это глоток свежего воздуха, в беспорядке рамок. Он проверяет свое эго у дверей и делает все возможное, чтобы помочь разработчику, а не бренду. Я болтал с разработчиками Sails и могу сказать, что в работах есть еще больше удивительности, и будет интересно посмотреть, куда идет этот фреймворк.

Итак, в заключение вы узнали, как настраивать, использовать и защищать ваши данные из Sails, а также как связывать их с популярной библиотекой Backbone.

Как и всегда, если у вас есть комментарии, не стесняйтесь оставлять их ниже или присоединяйтесь к нам на канале Nettuts + IRC («#nettuts» на freenode). Спасибо за чтение.