Пилотируем облачную MongoDB через VanillaJS или как бесплатно сделать приватный todo-лист за 15 минут

37e79ac537ec4d259d5e7ee2ab922f38.jpgНа фото: Том Круз в фильме Лучший СтрелокВ этой статье мы рассмотрим взаимодействие Single Page HTML Application с облачной MongoDB через JavaScript. В качестве MongoDB-as-a-Service я возьму Mongolab. Стоимость развернутой MongoDB, с объёмом в 500 мб, обойдется нам всего-лишь в 0 USD.Для того, чтобы создать todo-лист, нам не потребуется бекенд. Взаимодействовать с Mongolab мы будем через REST API, а обертку для него в клиентской части мы напишем не прибегая к помощи сторонних JavaScript-фреймворков.

Навигация по статье 1. Регистрация на Mongolab и получение API-ключа2. Безопасность данных при общении браузера с MongoDB3. Область применения подобных решений4. Давайте уже к делу5. Разбираем код приложения6. Демо готового проекта1. Регистрация на Mongolab и получение API-ключа Шаг первый — регистрируемся f1a17e8210724497b610c62f50a233c0.pngРегистрация простая и не требует привязки карт оплаты. Mongolab — довольно полезный сервис. В нашей компании мы используем его в качестве песочницы во время разработки веб-приложений.Шаг второй — заходим в меню пользователя bd531280d4954e37984cc05e6f544340.pngСправа на экране будет ссылка в пользовательское меню. В этом меню нас и будет ждать наш заветный API-key.Шаг третий — забираем API-ключ 94d7e5311c9d4756b32201082072c25d.pngПосле получения API-ключа мы можем работать с Mongolab REST API2. Безопасность данных при общении браузера с MongoDB 58df1fed8986451ab013348cfbac1a75.jpgНа фото: Том Круз смеётся Хочу предупредить — статья носит чисто учебный характер. Коммуникация с облачной базой данных из браузера может оказаться фатальной ошибкой. Думаю очевидно, что злоумышленник может легко получить доступ к базе просто открыв консоль разработчика. Использование read-only пользователя базы решает эту проблему только в том случае, если, абсолютно все данные находящиеся в облачной MongoDB — не несут никакой важности и приватности.3. Область применения подобных решений Основываясь на таком подходе мы с вами можем создать todo-list application, который можно будет держать у себя на компьютере, написать приложение под Android/iOS/Windows Phone/Windows 8.1 используя всего лишь один html и javascript.4. Давайте уже к делу На написание todo приложения у меня ушло ровно 15 минут, на написание этой статьи (+ комментирование кода) я потратил два часа. Цветовая схема была взята у Google, которую заботливо вынес в LESS один добрый человек. То, что у меня получилось, я залил на github чтобы вы смогли оценить работу с облачной базой не растрачивая своё драгоценное время. Ссылку вы найдёте в конце статьи.Коммуникацию с REST API будем осуществлять через XMLHttpRequest. Современный мир веб-разработки очень уверенно сфокусировался на решениях вроде jQuery или Angular — суют их везде и где попало. Зачастую обойтись можно спокойно и без них. Объект new XMLHttpRequest () — своего рода поток, связанный с js-объектом, у которого есть основные методы open и send (открыть соединение и отправить данные) и основное событие onreadystatechange. Для общения с REST нам потребуется установить заголовок Content-Type: application/json; charset=UTF-8, для этого мы используем метод setRequestHeader.

Вот так может выглядеть простое REST-приложение: var api = new XMLHttpRequest (); api.onreadystatechange = function () { if (this.readyState!= 4 || this.status!= 200) return; console.log (this.responseText); }; // вместо onreadystatechange можно использовать onload api.open ('GET', 'https://api.mongolab.com/api/1/databases? apiKey=XXX'); api.setRequestHeader ('Content-Type', 'application/json; charset=UTF-8'); api.send (); А метод вам не завернуть? var api = new XMLHttpRequest (); api.call = function (method, resource, data, callback) { this.onreadystatechange = function () { if (this.readyState!= 4 || this.status!= 200) return; return (callback instanceof Function) ? callback (JSON.parse (this.responseText)) : null; }; this.open (method, 'https://api.mongolab.com/api/1/' + resource + '? apiKey=XXX'); this.setRequestHeader ('Content-Type', 'application/json; charset=UTF-8'); this.send (data? JSON.stringify (data) : null); }; /** код ниже выглядит намного удобнее и его можно вызывать несколько раз */ api.call ('GET', 'databases', null, function (databases) { console.log (databases); }); Внести новую запись в коллекцию demo с title: test var test = { title: 'test' }; api.call ('POST', 'databases/mydb/demo', test, function (result) { test = result; // получить ID из базы после добавления }); Проблема синхронного потока Наша переменная api является лишь одним потоком, поэтому следующий код ошибочен: api.call ('POST', 'databases/mydb/demo', test1); api.call ('POST', 'databases/mydb/demo', test2); Для того, чтобы обойти синхронность, нам потребуется два отдельных потока — для первого POST и для второго. Чтобы каждый раз не описывать метод call — мы приходим к решению собрать «псевдо-класс» MongoRESTRequest, который на самом деле являлся бы функцией, возвращающей новый объект XMLHttpRequest с готовым методом call: var MongoRESTRequest = function () { var api = new XMLHttpRequest (); api.call = function (method, resource, data, callback) { this.onreadystatechange = function () { if (this.readyState!= 4 || this.status!= 200) return; return (callback instanceof Function) ? callback (JSON.parse (this.responseText)) : null; }; this.open (method, 'https://api.mongolab.com/api/1/' + resource + '? apiKey=XXX'); this.setRequestHeader ('Content-Type', 'application/json; charset=UTF-8'); this.send (data? JSON.stringify (data) : null); }; return api; };

var api1 = new MongoRESTRequest (); var api2 = new MongoRESTRequest (); api1.call ('POST', 'databases/mydb/demo', test1); api2.call ('POST', 'databases/mydb/demo', test2); Теперь этот код будет исполнен корректно.Продолжая модифицировать наш MongoRESTRequest мы придём приблизительно к тому варианту, который будет изложен в исходном коде приложения ниже.Немного про то, как можно обойтись без шаблонизатора: Обычно я наблюдаю в коде среднестатистического фаната jQuery нечто такое: $('#myDiv').html ('

'); А теперь взгляните, как это должно быть на самом деле, без подключения лишних 93.6 кб (compressed, production jQuery 1.11.2) var myDiv = document.getElementById ('myDiv'); var newDiv = document.createElement ('div'); // создать div newDiv.classList.add ('red'); // добавить класс red myDiv.appendChild (newDiv); // вставить в myDiv Ладно, ладно, конечно все мы знаем что это можно сделать и так: document.getElementById ('myDiv').innerHTML = '
'; Ещё немного про работу с DOM в Vanilla: Используем map для создания списка (ReactJS-way): var myList = document.getElementById ('myList'); var items = ['первый', 'второй', 'третий']; items.map (function (item) { var itemElement = document.createElement ('li'); itemElement.appendChild (document.createTextNode (item)); myList.appendChild (itemElement); }); На выходе имеем (ссылка на jsFiddle поиграться):
  • первый
  • второй
  • третий
Преимуществом такой работы JavaScript является возможность полноценной работы с объектами: var myList = document.getElementById ('myList'); var items = [{id: 1, name: 'первый'}, {id: 2, name: 'второй'}, {id: 3, name: 'третий'}]; items.map (function (item) { var itemElement = document.createElement ('li'); itemElement.appendChild (document.createTextNode (item.name)); itemElement.objectId = item.id; // присваиваем свойство objectId для каждого itemElement itemElement.onclick = function () { alert ('item #' + this.objectId); }; myList.appendChild (itemElement); }); Ссылка на jsFiddle для проверки5. Разбираем код приложения Я постарался прокомментировать каждую строчку кода Список дел
Список дел
Как изменить цветовую схему всего проекта, поменяв всего одну переменную В файле main.less имеется следующий код (приведен не до конца, главное понять суть): @import 'palette';

@themeRed: 'red'; @themePink: 'pink'; @themePurple: 'purple'; @themeDeepPurple: 'deep-purple'; @themeIndigo: 'indigo'; @themeBlue: 'blue'; @themeLightBlue: 'light-blue'; @themeCyan: 'cyan'; @themeTeal: 'teal'; @themeGreen: 'green'; @themeLightGreen: 'light-green'; @themeLime: 'lime'; @themeYellow: 'yellow'; @themeAmber: 'amber'; @themeOrange: 'orange'; @themeDeepOrange: 'deep-orange'; @themeBrown: 'brown'; @themeGrey: 'grey'; @themeBlueGrey: 'blue-grey';

/** * http://www.google.com/design/spec/style/color.html#color-color-palette * thanks to https://github.com/shuhei/material-colors */ @theme: @themeBlueGrey;

@r50: 'md-@{theme}-50'; @r100: 'md-@{theme}-100'; @r200: 'md-@{theme}-200'; @r300: 'md-@{theme}-300'; @r400: 'md-@{theme}-400'; @r500: 'md-@{theme}-500'; @r600: 'md-@{theme}-600'; @r700: 'md-@{theme}-700'; @r800: 'md-@{theme}-800'; @r900: 'md-@{theme}-900';

@color50: @@r50; @color100: @@r100; @color200: @@r200; @color300: @@r300; @color400: @@r400; @color500: @@r500; @color600: @@r600; @color700: @@r700; @color800: @@r800; @color900: @@r900;

@font-face { font-family: 'Roboto Medium'; src: url ('…/fonts/Roboto-Regular.ttf') format ('truetype'); }

body { font-family: 'Roboto Medium', Roboto, sans-serif; font-size: 24 px; background-color: @color900; color: @color50; margin: 0; padding: 0; } Меняем @theme на любую из перечисленных и при этом получаем изменение темы всего приложения целиком. Раньше я не раз вытворял подобные трюки с LESS. К примеру можно делать таким образом (можете расценить это как бонус для людей, которые никогда не видели LESS): @baseColor: #000000; @textColor: contrast (@baseColor); @someLightenColor: lighten (@baseColor, 1%); 6. Демо готового проекта Достаточно рискованно размещать тут ссылку на демо, так как база всё же free.fd813930df774783a586a6eb948e6dce.pngНа случай если упадёт: это выглядело как-то так как на этом скриншоте → Заветная демка тут→ Исходный код демки на GitHub

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

© Habrahabr.ru