Излишно е да споменаваме нарастващата популярност на Node.js за разработване на приложения. eBay работи с производствена услуга за API на Node от 2011 г. PayPal активно възстановява своя интерфейс в Node. Мобилният сайт на Walmart се превърна в най-голямото приложение на Node от гледна точка на трафика. През уикенда на Деня на благодарността през 2014 г. Сървърите на Walmart обработиха 1,5 милиарда заявки , 70 процента от които са доставени чрез мобилни устройства и се захранват от Node.js. От страна на разработката, мениджърът на пакети Node ( над морското равнище ) продължава да расте бързо, наскоро надминавайки 150 000 хоствани модула.
Докато Руби има релси и Python има Django, доминиращата рамка за разработка на приложения за Node все още не е установена. Но има мощен претендент, който набира пара: LoopBack , рамка на API с отворен код, създадена от компанията San Mateo, Калифорния StrongLoop . StrongLoop има важен принос за най-новите Версия на възела , да не говорим за дългогодишните поддръжници на Експрес , една от най-популярните съществуващи рамки на Node.
Нека разгледаме по-отблизо LoopBack и неговите възможности, като превърнем всичко на практика и създадем примерно приложение.
LoopBack е рамка за създаване на API и свързването им с бекенд източници на данни. Построен върху Express, той може да вземе дефиниция на модел на данни и лесно да генерира напълно функционален REST API от край до край, който може да бъде извикан от всеки клиент.
LoopBack се предлага с вграден клиент, API Explorer . Ще използваме това, тъй като улеснява виждането на резултатите от нашата работа и така нашият пример може да се съсредоточи върху изграждането на самия API.
Разбира се, ще ви е необходим Node, инсталиран на вашата машина, за да го следвате. Вземи го тук . npm идва с него, така че можете лесно да инсталирате необходимите пакети. Да започваме.
Нашето приложение ще управлява хора, които биха искали да дарят подаръци или неща, от които просто вече не се нуждаят, на някой, който може да се нуждае от тях. Така че потребителите ще бъдат дарители и получатели. Дарител може да създаде нов подарък и да види списъка с подаръци. Получателят може да види списъка с подаръци от всички потребители и може да претендира за всички, които не са заявени. Разбира се, бихме могли да изградим донори и получатели като отделни роли на едно и също лице (Потребител), но нека опитаме да ги разделим, за да можем да видим как да изградим отношения в LoopBack. Името на това новаторско приложение ще бъде Дава някой .
Инсталирайте инструментите на командния ред StrongLoop чрез npm:
$ npm install -g strongloop
След това стартирайте генератора на приложения на LoopBack:
$ slc loopback _-----_ | | .--------------------------. |--(o)--| | Let's create a LoopBack | `---------´ | application! | ( _´U`_ ) '--------------------------' /___A___ | ~ | __'.___.'__ ´ ` |° ´ Y ` ? What's the name of your application? Givesomebody
Нека добавим модел. Първият ни модел ще се казва Подарък. LoopBack ще поиска източника на данни и базовия клас. Тъй като все още не сме настроили източника на данни, можем да поставим db (memory)
. Основният клас е автоматично генериран клас на модел и ние искаме да използваме PersistedModel
в този случай, тъй като вече съдържа всички обичайни за нас CRUD методи. След това LoopBack пита дали трябва да изложи модела чрез REST (да) и името на REST услугата. Натиснете Enter тук, за да използвате подразбирането, което е просто множествено число на името на модела (в нашия случай gifts
).
$ slc loopback:model ? Enter the model name: Gift ? Select the data-source to attach Gift to: (Use arrow keys) ❯ db (memory) ? Select model's base class: (Use arrow keys) Model ❯ PersistedModel ? Expose Gift via the REST API? (Y/n) Yes ? Custom plural form (used to build REST URL):
И накрая, даваме имената на свойствата, техните типове данни и задължителните / ненужните флагове. Подаръкът ще има name
и description
Имоти:
Let's add some Gift properties now. Enter an empty property name when done. ? Property name: name invoke loopback:property ? Property type: (Use arrow keys) ❯ string ? Required? (y/N)Yes
Въведете празно име на свойството, за да посочите, че сте готови с дефинирането на свойствата.
Генераторът на модели ще създаде два файла, които определят модела в приложението common/models
: gift.json
и gift.js
. JSON файлът определя всички метаданни за обекта: свойства, отношения, проверки, роли и имена на методи. JavaScript файлът се използва за дефиниране на допълнително поведение и за определяне на отдалечени куки, които да се извикват преди или след определени операции (напр. Създаване, актуализиране или изтриване).
Другите два моделни единици ще бъдат нашите модели на донори и получатели. Можем да ги създадем, като използваме същия процес, с изключение на този път нека поставим User
като основен клас. Това ще ни даде някои свойства като username
, password
, email
извън кутията. Можем да добавим само име и държава, например, за да имаме пълен обект. За Получателя искаме да добавим и адреса за доставка.
Нека да разгледаме генерираната структура на проекта:
Трите основни директории са: - /server
- Съдържа скриптове за приложения на възли и конфигурационни файлове. - /client
- Съдържа .js, .html, .css и всички други статични файлове. - /common
- Тази папка е обща както за сървъра, така и за клиента. Файловете с модели отиват тук.
Ето подробна разбивка на съдържанието на всяка директория, взета от LoopBack документация :
Файл или директория | Описание | Как да вляза в код |
---|---|---|
Директория с приложения на най-високо ниво | ||
package.json | Стандартна спецификация на пакета npm. Вижте package.json | Неприложимо |
/ сървърна директория - Node файлове на приложения | ||
server.js | Основен файл на приложната програма. | Неприложимо |
config.json | Настройки на приложението. Вижте config.json . | app.get('setting-name') |
datasources.json | Конфигурационен файл на източника на данни. Вижте datasources.json .За пример вижте Създайте нов източник на данни . | app.datasources['datasource-name'] |
model-config.json | Конфигурационен файл на модел. Вижте model-config.json .За повече информация вижте Свързване на модели към източници на данни . | Неприложимо |
middleware.json | Файл с дефиниция на Middleware. За повече информация вижте Дефиниране на междинен софтуер . | Неприложимо |
/boot директория | Добавете скриптове, за да извършите инициализация и настройка. Вижте скриптове за зареждане . | Скриптовете се изпълняват автоматично по азбучен ред. |
/ клиентска директория - файлове на клиентско приложение | ||
README.md | Генераторите на LoopBack създават празен README файл във формат за намаление. | Неприложимо |
Други | Добавете вашите HTML, CSS, клиентски JavaScript файлове. | |
/ обща директория - споделени файлове на приложения | ||
/models директория | Файлове на персонализиран модел:
| Възел: myModel = app.models.myModelName |
В нашия пример имаме няколко важни взаимоотношения, които да моделираме. Дарител може да дари много подаръци, което дава връзка Дарителят има много подаръци . Получателят може също да получи много подаръци, така че ние също имаме връзка Получателят има много подаръци . От друга страна, Подаръкът принадлежи на дарителя и може също принадлежат на Получателя ако Получателят реши да го приеме. Нека да сложим това на езика на LoopBack.
$ slc loopback:relation ? Select the model to create the relationship from: Donor ? Relation type: has many ? Choose a model to create a relationship with: Gift ? Enter the property name for the relation: gifts ? Optionally enter a custom foreign key: ? Require a through model? No
Имайте предвид, че няма проходен модел; ние просто държим препратката към Подаръка.
Ако повторим горната процедура за приемник и добавим две принадлежи на отношения с Подарък, ще изпълним дизайна на модела си отзад. LoopBack автоматично актуализира JSON файловете за моделите, за да изрази точно това, което току-що направихме чрез тези прости диалогови прозорци:
// common/models/donor.json ... 'relations': { 'gifts': { 'type': 'hasMany', 'model': 'Gift', 'foreignKey': '' } }, ...
Сега нека видим как да прикачите реален източник на данни, за да съхранявате всички наши данни за приложения. За целите на този пример ще използваме MongoDB , но LoopBack има модули за свързване с Oracle, MySQL, PostgreSQL, Redis и SQL Server.
Първо инсталирайте съединителя:
$ npm install --save loopback-connector-mongodb
След това добавете източник на данни към вашия проект:
$ slc loopback:datasource ? Enter the data-source name: givesomebody ? Select the connector for givesomebody: MongoDB (supported by StrongLoop)
Следващата стъпка е да конфигурирате своя източник на данни в server/datasources.json
. Използвайте тази конфигурация за локален сървър MongoDB:
... 'givesomebody': { 'name': 'givesomebody', 'connector': 'mongodb', 'host': 'localhost', 'port': 27017, 'database': 'givesomebody', 'username': '', 'password': '' } ...
Накрая отворете server/model-config.json
и променете datasource
за всички обекти, които искаме да продължим в базата данни, да 'givesomebody'
.
{ ... 'User': { 'dataSource': 'givesomebody' }, 'AccessToken': { 'dataSource': 'givesomebody', 'public': false }, 'ACL': { 'dataSource': 'givesomebody', 'public': false }, 'RoleMapping': { 'dataSource': 'givesomebody', 'public': false }, 'Role': { 'dataSource': 'givesomebody', 'public': false }, 'Gift': { 'dataSource': 'givesomebody', 'public': true }, 'Donor': { 'dataSource': 'givesomebody', 'public': true }, 'Receiver': { 'dataSource': 'givesomebody', 'public': true } }
Време е да видим какво сме изградили досега! Ще използваме страхотния вграден инструмент, API Explorer , който може да се използва като клиент за услугата, която току-що създадохме. Нека опитаме да тестваме REST API обаждания.
В отделен прозорец стартирайте MongoDB с:
$ mongod
Стартирайте приложението с:
$ node .
В браузъра си отидете на http://localhost:3000/explorer/
. Можете да видите обектите си със списъка с налични операции. Опитайте да добавите един дарител с POST /Donors
обадете се.
API Explorer е много интуитивен; изберете някой от изложените методи и съответната схема на модела ще се покаже в долния десен ъгъл. В data
текстова област, възможно е да се напише персонализирана HTTP заявка. След като заявката бъде попълнена, щракнете върху бутона „Изпробвайте“ и отговорът на сървъра ще се покаже по-долу.
Както бе споменато по-горе, един от обектите, който идва предварително изграден с LoopBack, е потребителският клас. Потребителят притежава методи за влизане и излизане и може да бъде обвързан с обект AccessToken, който съхранява маркера на конкретния потребител. Всъщност пълна система за удостоверяване на потребителя е готова да излезе от кутията. Ако се опитаме да се обадим /Donors/login
през API Explorer , ето отговорът, който получаваме:
{ 'id': '9Kvp4zc0rTrH7IMMeRGwTNc6IqNxpVfv7D17DEcHHsgcAf9Z36A3CnPpZJ1iGrMS', 'ttl': 1209600, 'created': '2015-05-26T01:24:41.561Z', 'userId': '' }
id
всъщност е стойността на AccessToken, генерирана и запазена в базата данни автоматично. Както виждате тук, възможно е да зададете маркер за достъп и да го използвате за всяка следваща заявка.
Отдалеченият метод е статичен метод на модел, изложен през персонализирана REST крайна точка. Отдалечените методи могат да се използват за извършване на операции, които не са предоставени от стандартния модел REST API на LoopBack.
Освен методите CRUD, които изваждаме от кутията, можем да добавим толкова персонализирани методи, колкото искаме. Всички те трябва да отидат в [model].js
файл. В нашия случай нека добавим отдалечен метод към модела за подаръци, за да проверим дали подаръкът вече е резервиран, и един, за да изброим всички подаръци, които не са резервирани.
Първо, нека добавим допълнително свойство към модела, наречено reserved
. Просто добавете това към свойствата в gift.json
:
... 'reserved': { 'type': 'boolean' } ...
Отдалеченият метод в gift.js
трябва да изглежда по следния начин:
module.exports = function(Gift) { // method which lists all free gifts Gift.listFree = function(cb) { Gift.find({ fields: { reserved: false } }, cb); }; // expose the above method through the REST Gift.remoteMethod('listFree', { returns: { arg: 'gifts', type: 'array' }, http: { path: '/list-free', verb: 'get' } }); // method to return if the gift is free Gift.isFree = function(id, cb) { var response; Gift.find({ fields: { id: id } }, function(err, gift) { if (err) return cb(err); if (gift.reserved) response = 'Sorry, the gift is reserved'; else response = 'Great, this gift can be yours'; }); cb(null, response); }; // expose the method through REST Gift.remoteMethod('isFree', { accepts: { arg: 'id', type: 'number' }, returns: { arg: 'response', type: 'string' }, http: { path: '/free', verb: 'post' } }); };
Така че, за да разбере дали е наличен конкретен подарък, клиентът вече може да изпрати POST заявка до /api/Gifts/free
, като предава id
от въпросния подарък.
Понякога има нужда от изпълнение на някакъв метод преди или след отдалечения метод. Можете да дефинирате два вида отдалечени куки:
beforeRemote()
работи преди отдалечения метод.afterRemote()
работи след отдалечения метод.И в двата случая предоставяте два аргумента: низ, който съответства на отдалечения метод, към който искате да „закачите“ вашата функция, и функцията за обратно извикване. Голяма част от силата на отдалечените куки е, че низът може да включва заместващи символи, така че се задейства от всеки метод на съвпадение.
В нашия случай, нека зададем кука за отпечатване на информация на конзолата, когато се създава нов дарител. За да постигнем това, нека добавим кука „преди създаване“ в donor.js
:
module.exports = function(Donor) { Donor.beforeRemote('create', function(context, donor, next) { console.log('Saving new donor with name: ', context.req.body.name); next(); }); };
Заявката се извиква с дадените context
, а next()
обратното обаждане в междинния софтуер (обсъдено по-долу) се извиква след изпълнението на куката
Приложенията LoopBack имат достъп до данни чрез модели, така че контролирането на достъпа до данни означава дефиниране на ограничения върху моделите; тоест посочване кой или какво може да чете и записва данните или да изпълнява методи на моделите. LoopBack контролите за достъп се определят от списъци за контрол на достъпа или ACL.
Нека позволим нерегистрирани дарители и получатели да разглеждат подаръци, но само влезли дарители да ги създават и изтриват.
$ slc loopback:acl
За начало нека откажем достъп на всички до всички крайни точки.
? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: All methods and properties ? Select the access type: All (match all types) ? Select the role: All users ? Select the permission to apply: Explicitly deny access
След това позволете на всички да четат от модели за подаръци:
$ slc loopback:acl ? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: All methods and properties ? Select the access type: Read ? Select the role: All users ? Select the permission to apply: Explicitly grant access
След това искаме да позволим на удостоверени потребители да създават подаръци:
$ slc loopback:acl ? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: A single method ? Enter the method name: create ? Select the role: Any authenticated user ? Select the permission to apply: Explicitly grant access
И накрая, нека позволим на собственика на подаръка да направи промени:
$ slc loopback:acl ? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: All methods and properties ? Select the access type: Write ? Select the role: The user owning the object ? Select the permission to apply: Explicitly grant access
Сега, когато преглеждаме gift.json
, всичко трябва да е на мястото си:
'acls': [ { 'accessType': '*', 'principalType': 'ROLE', 'principalId': '$everyone', 'permission': 'DENY' }, { 'accessType': 'READ', 'principalType': 'ROLE', 'principalId': '$everyone', 'permission': 'ALLOW' }, { 'accessType': 'EXECUTE', 'principalType': 'ROLE', 'principalId': '$authenticated', 'permission': 'ALLOW', 'property': 'create' } ],
Една важна забележка тук: $authenticated
е предварително дефинирана роля, която отговаря на всички потребители в системата (както дарители, така и получатели), но ние искаме само да позволим на дарителите да създават нови подаръци. Следователно се нуждаем от персонализирана роля. Тъй като Role е още един обект, който излизаме от кутията, можем да използваме неговото API извикване, за да създадем $authenticatedDonor
роля във функцията за зареждане и след това просто модифицирайте pricipalId
в gift.json
.
Ще е необходимо да създадете нов файл, server/boot/script.js
и да добавите следния код:
Role.create({ name: 'authenticatedDonor' }, function(err, role) { if (err) return debug(err); })
Обектът RoleMapping картографира ролите на потребители. Уверете се, че и Role, и RoleMapping са изложени чрез REST. В server/model-config.json
проверете дали 'public'
е зададено на true
за обекта Роля. След това в donor.js
можем да напишем кука 'преди създаване', която ще нанесе userID
и roleID
в извикването на POST API на RoleMapping.
Middleware съдържа функции, които се изпълняват, когато се направи заявка до крайната точка REST. Тъй като LoopBack е базиран на Express, той използва Express Middleware с една допълнителна концепция, наречена „фази на middleware“. Фазите се използват за ясно дефиниране на реда, в който се извикват функциите в междинния софтуер.
Ето списъка с предварително дефинирани фази, както е предоставено в документите LoopBack:
Всяка фаза има три подфази. Например подфазите на началната фаза са:
Нека да разгледаме набързо нашия по подразбиране middleware.json:
{ 'initial:before': { 'loopback#favicon': {} }, 'initial': { 'compression': {}, 'cors': { 'params': { 'origin': true, 'credentials': true, 'maxAge': 86400 } } }, 'session': { }, 'auth': { }, 'parse': { }, 'routes': { }, 'files': { }, 'final': { 'loopback#urlNotFound': {} }, 'final:after': { 'errorhandler': {} } }
В началната фаза наричаме loopback.favicon()
(loopback#favicon
е идентификационният номер на междинния софтуер за това обаждане). След това, npm модули на трети страни compression
и cors
се извикват (със или без параметри). Във финалната фаза имаме още две обаждания. urlNotFound
е LoopBack повикване и errorhandler
е модул на трета страна. Този пример трябва да демонстрира, че много вградени повиквания могат да се използват точно като външните модули npm. И разбира се, винаги можем да създадем свой собствен междинен софтуер и да ги извикаме през този JSON файл.
loopback-boot
За да завършим, нека споменем модул, който експортира boot()
функция, която инициализира приложението. В server/server.js
ще намерите следния код, който стартира приложението:
boot(app, __dirname, function(err) { if (err) throw err; // start the server if `$ node server.js` if (require.main === module) app.start(); });
Този скрипт ще търси server/boot
папка и заредете всички скриптове, които намери там, по азбучен ред. По този начин в server/boot
можем да посочим всеки скрипт, който трябва да се стартира при стартиране. Един пример е explorer.js
, който работи API Explorer , клиентът, който използвахме за тестване на нашия API.
Преди да ви напусна, бих искал да спомена StrongLoop Arc , графичен потребителски интерфейс, който може да се използва като алтернатива на slc
инструменти за команден ред. Той също така включва инструменти за изграждане, профилиране и наблюдение на Node приложения. За тези, които не са фенове на командния ред, това определено си струва да се опита. Въпреки това, StrongLoop Arc е на път да бъде остарял и неговата функционалност е интегрирана в IBM API Connect Developer Toolkit .
Най-общо казано, LoopBack може да ви спести много ръчна работа, тъй като изваждате много неща от кутията. Тя ви позволява да се съсредоточите върху специфични за приложението проблеми и бизнес логика. Ако молбата ви е въз основа на CRUD операции и манипулиране на предварително дефинирани обекти, ако ви е писнало да пренаписвате инфраструктурата за удостоверяване и упълномощаване на потребителя, когато множество разработчици са написали това преди вас, или ако искате да се възползвате от всички предимства на страхотна уеб рамка като Express, след това изграждане на вашия REST API с LoopBack може да сбъдне мечтите ви. Лесна работа!