Loopback е създаден като рамка с отворен код за мобилен бекенд като услуга от Strongloop. Той ви позволява да настроите REST API за минути и е базиран на Express.

В тази публикация ще използваме версия 3.4.0, за да създадем API за резервации за къмпинг:

Приготвяме се да започнем

Loopback идва с CLI инструмент за генериране на приложение. Можете да конфигурирате всичко ръчно, но CLI инструментът е наистина удобен подарък, за да започнете. Инсталирайте го чрез мениджъра на пакети на възли: npm install -g loopback-cli

Когато е инсталиран, въведете lb, за да стартирате yeoman-generator:

     _-----_     
    |       |    ╭──────────────────────────╮
    |--(o)--|    │  Let's create a LoopBack │
   `---------´   │       application!       │
    ( _´U`_ )    ╰──────────────────────────╯
    /___A___\   /
     |  ~  |     
   __'.___.'__   
 ´   `  |° ´ Y ` 

? What's the name of your application? reservations
? Enter name of the directory to contain the project: reservations
   create reservations/
     info change the working directory to reservations

? Which version of LoopBack would you like to use? 3.x (current)
? What kind of application do you have in mind? empty-server (An empty LoopBack API, without any configured models or datasources)

Когато приключите, ще видите следната структура на проекта. JSON файловете са за конфигурация, а Javascript файловете са за разширяване на Express.

reservations/ 
├── client                       # Client JS, HTML and CSS files
│ └── README.md                  # Empty README.md file
├── package.json                 # Npm package specification
└── server                       # Node scripts and config 
 ├── boot                        # Initialization scripts
 │ └── root.js                   # Specify the contextroot
 ├── component-config.json       # Loopback components config
 ├── config.json                 # Global settings
 ├── datasources.json            # Datasource config
 ├── middleware.development.json # Middleware config for dev
 ├── middleware.json             # Middleware config
 ├── model-config.json           # Binds models to datasources
 └── server.js                   # Main application script

Отидете в папката с резервации и стартирайте приложението, като стартирате npm start. Отворете http://localhost:3000/explorer във вашия браузър, за да видите основен Swagger-UI

Упоритост

Погледнете server/datasources.json. Все още нямаме конфигурирани източници на данни. Тук ще използваме база данни в паметта, но има много „достъпни конектори за база данни“ извън кутията.

Въведете lb datasource, за да стартирате генератора отново.

? Enter the data-source name: reservationDS
? Select the connector for reservationDS: In-memory db (supported by StrongLoop)
Connector-specific configuration:
? window.localStorage key to use for persistence (browser only): 
? Full path to file for persistence (server only): db.json

Файлът db.json ще запази данните в паметта във файл. Това ни позволява да запазим данните си, когато рестартираме сървъра. Също така ни позволява да стартираме нашето приложение с някои тестови данни.

Ще създадем този файл по-късно. Loopback няма да даде предупреждение, когато този файл все още не е наличен.

Модели

Loopback е проектиран около концепцията за „модели“. Нека създадем модел за нашия лагер, lb модел

? Enter the model name: campground
? Select the data-source to attach campground to: reservationDS (memory)
? Select model's base class PersistedModel
? Expose campground via the REST API? Yes
? Custom plural form (used to build REST URL): 
? Common model or server only? server
Let's add some campground properties now.

Enter an empty property name when done.
? Property name: name
   invoke   loopback:property
? Property type: string
? Required? Yes
? Default value[leave blank for none]: 

Let's add another campground property.
Enter an empty property name when done.
? Property name: location
   invoke   loopback:property
? Property type: geopoint
? Required? No
? Default value[leave blank for none]: 

Let's add another campground property.
Enter an empty property name when done.
? Property name:

Създадохме модела на лагера и го извлечехме от PersistedModel, така че можем да го запазим в нашия източник на данни. Можете да направите модел общ, което означава, че същият модел може да се споделя между клиента и
сървъра, но ние решихме да го използваме само за сървъра.

Нашият модел има 2 свойства, име и местоположение. Свойството id се включва автоматично, така че не е нужно да го добавяте.

Посетете API Explorer на http://localhost:3000/explorer. Сега ще видите много налични крайни точки за нашите
къмпинги.

Нека тестваме нашия API, като вземем всички къмпинги:

curl -X GET 'http://localhost:3000/api/campgrounds'

Тъй като нямаме никакви данни, отговорът ще бъде празен списък. Сега създаваме файла db.json, който посочихме в предишния раздел. Създайте файл db.json в основата на проекта.

{
  "ids": {
    "campground": 5
  },
  "models": {
     "campground": {
       "1": "{\"name\":\"Salt Lake City KOA\",\"location\":{\"lat\": 40.772112, \"lng\": -111.932165},\"id\":1}",
       "2": "{\"name\":\"Gouldings Campground\",\"location\":{\"lat\": 37.006989, \"lng\": -110.214907},\"id\":2}",
       "3": "{\"name\":\"Grand Canyon Mather Campground\",\"location\":{\"lat\": 36.056472, \"lng\": -112.140728},\"id\":3}",
       "4": "{\"name\":\"Camping Paris Bois de Boulogne\",\"location\":{\"lat\": 48.868879, \"lng\": 2.234914},\"id\":4}"
     }
  }
}

Рестартирайте сървъра и опитайте отново. Сега трябва да видите 4 къмпинга.
Ще завършим тази част, като генерираме нашия резервационен модел, lb модел:

? Enter the model name: reservation
? Select the data-source to attach reservation to: reservationDS (memory)
? Select model's base class PersistedModel
? Expose reservation via the REST API? Yes
? Custom plural form (used to build REST URL): 
? Common model or server only? server
Let's add some reservation properties now.

Enter an empty property name when done.
? Property name: startDate
   invoke   loopback:property
? Property type: date
? Required? Yes
? Default value[leave blank for none]: 

Let's add another reservation property.
Enter an empty property name when done.
? Property name: endDate
   invoke   loopback:property
? Property type: date
? Required? Yes
? Default value[leave blank for none]: 

Let's add another reservation property.
Enter an empty property name when done.
? Property name:

Връзки

Къмпингите могат да имат нула или повече резервации. Трябва да създадем „връзка между нашите модели“, за да постигнем това, lb връзка:

? Select the model to create the relationship from: campground
? Relation type: has many
? Choose a model to create a relationship with: reservation
? Enter the property name for the relation: reservations
? Optionally enter a custom foreign key: 
? Require a through model? No

Стартирайте сървъра отново и отидете на API Explorer. Ще видите някои нови крайни точки за /campgrounds/{id}/reservations.

Нека актуализираме нашите тестови данни, така че да имаме няколко резервации за нашите къмпинги.

{
  "ids": {
    "campground": 5,
    "reservation": 2
  },
  "models": {
     "campground": {
       "1": "{\"name\":\"Salt Lake City KOA\",\"location\":{\"lat\": 40.772112, \"lng\": -111.932165},\"id\":1}",
       "2": "{\"name\":\"Gouldings Campground\",\"location\":{\"lat\": 37.006989, \"lng\": -110.214907},\"id\":2}",
       "3": "{\"name\":\"Grand Canyon Mather Campground\",\"location\":{\"lat\": 36.056472, \"lng\": -112.140728},\"id\":3}",
       "4": "{\"name\":\"Camping Paris Bois de Boulogne\",\"location\":{\"lat\": 48.868879, \"lng\": 2.234914},\"id\":4}"
     },
     "reservation": {
       "1": "{\"startDate\":\"2017-03-21\",\"endDate\":\"2017-03-23\",\"campgroundId\":1,\"id\":1}",
       "2": "{\"startDate\":\"2017-03-25\",\"endDate\":\"2017-03-31\",\"campgroundId\":2,\"id\":2}"
     }
  }
}

Запитвания

Крайните точки за обратна връзка могат също да се използват за „запитване за конкретни данни“.
Ето селекция от това, което е възможно извън кутията:

  • Показване на всички къмпинги с „KOA“ в име
    /api/campgrounds?filter[where][name][like]=KOA
  • Показване на всички резервации след или на 22 март 2017 г.
    /api/reservations?filter[where][startDate][gte]=22 март 2017 г.
  • Показване само на имената на къмпингите:
    /api/campgrounds?filter[fields][name]=true
  • Показване на всичко освен имената на къмпингите:
    /api/campgrounds?filter[fields][name]
  • Покажете къмпингите и включете техните резервации:
    /api/campgrounds?filter[include][reservations]
  • Покажете първите 2 къмпинга:
    /api/campgrounds?filter[limit]=2
  • Покажете следващите 2 къмпинга:
    /api/campgrounds?filter[skip]=2&filter[limit]=2
  • Подредете къмпингите по име
    /api/campgrounds?filter[order]=name
  • Къмпинги в низходящ ред по име:
    /api/campgrounds?filter[order]=name%20DESC

Геолокация

Можете също да правите заявки въз основа на геолокация. Местоположението на нашия къмпинг е гео точка.
Представете си, че сме в Националния парк Arches и искаме да търсим всички къмпинги в радиус от 200 мили:

/api/campgrounds?filter[where][location][near]=38.7006538,-109.5643742&filter[where][location][maxDistance]=200

Валидиране

Когато създадохме модела на лагера, направихме необходимото име. Ако се опитаме да създадем къмпинг без име, loopback ще ни даде грешка при валидиране, че полето не може да бъде празно.

Loopback също има някои вградени методи за валидиране за често
използвано валидиране. Името на нашия къмпинг трябва да има макс. 100 знака. Можем да приложим това, като добавим следния код към server/models/campground.js:

'use strict';

module.exports = function(Campground) {
 Campground.validatesLengthOf('name', {max: 100, message: {max: 'Name is too long'}});
};

Можете също да добавите персонализирано валидиране. За резервация крайната дата трябва да е след началната дата:

'use strict';

module.exports = function(Reservation) {
  Reservation.validate('startDate', dateValidator, {message: 'endDate should be after startDate'});
    function dateValidator(err) {
      if(this.startDate >= this.endDate) {
        err();
      }
    }
};

Сигурност

Всички наши крайни точки са публични. Трябва да добавим малко сигурност тук. Нашият пример ще има 3 типа потребители. Анонимните потребители трябва да могат да виждат всички къмпинги. Когато се регистрират, те ще станат клиенти, които могат да правят резервации и могат да виждат само там собствените си резервации.

Администраторите трябва да могат да виждат и правят всичко. Loopback има
вградени модели за сигурност, но се препоръчва да не ги използвате директно.

Ние ще създадем клиентски модел, който се разширява от потребителския модел. lb модел:

? Enter the model name: customer
? Select the data-source to attach customer to: reservationDS (memory)
? Select model's base class User
? Expose customer via the REST API? Yes
? Custom plural form (used to build REST URL): 
? Common model or server only? server
Let's add some customer properties now.

Enter an empty property name when done.
? Property name: name
   invoke   loopback:property
? Property type: string
? Required? No
? Default value[leave blank for none]: 

Let's add another customer property.
Enter an empty property name when done.
? Property name: 

Клиентите могат да имат нула или повече резервации. Нека създадем връзка тук, lb връзка:

? Select the model to create the relationship from: customer
? Relation type: has many
? Choose a model to create a relationship with: reservation
? Enter the property name for the relation: reservations
? Optionally enter a custom foreign key: 
? Require a through model? No

Тъй като започнахме от празен сървър, вградените модели не са дефинирани в server/model-config.json. Нека ги добавим сега.

Задаването на свойството 'public' на false означава, че те няма да бъдат публични и няма да се показват в нашия API Explorer.

{
  "_meta": {
    "sources": [
      "loopback/common/models",
      "loopback/server/models",
      "../common/models",
      "./models"
    ],
    "mixins": [
      "loopback/common/mixins",
      "loopback/server/mixins",
      "../common/mixins",
      "./mixins"
    ]
  },
  "campground": {
    "dataSource": "reservationDS",
    "public": true
  },
  "reservation": {
    "dataSource": "reservationDS",
    "public": true
  },
  "customer": {
    "dataSource": "reservationDS",
    "public": true
  },
  "User": {
    "dataSource": "reservationDS",
    "public": false
  },
  "AccessToken": {
    "dataSource": "reservationDS",
    "public": false
  },
  "ACL": {
    "dataSource": "reservationDS",
    "public": false
  },
  "RoleMapping": {
    "dataSource": "reservationDS",
    "public": false
  },
  "Role": {
    "dataSource": "reservationDS",
    "public": false
  }
}

Сега ще добавим 3 потребители към приложението:

  • Анди, нашият администратор: (потребителско име: andy, парола: andy)
  • Кенет, клиент: (потребителско име: кенет, парола: кенет)
  • Claudiu, друг клиент: (потребителско име: claudiu, парола: claudiu)

Паролите трябва да бъдат хеширани във файла db.json. Ние също така свързваме нашите резервации с нашите клиенти.

{
  "ids": {
    "campground": 5,
    "reservation": 3,
    "customer": 4,
    "AccessToken": 1,
    "ACL": 1,
    "RoleMapping": 1,
    "Role": 1
  },
  "models": {
    "campground": {
      "1": "{\"name\":\"Salt Lake City KOA\",\"location\":{\"lat\": 40.772112, \"lng\": -111.932165},\"id\":1}",
      "2": "{\"name\":\"Gouldings Campground\",\"location\":{\"lat\": 37.006989, \"lng\": -110.214907},\"id\":2}",
      "3": "{\"name\":\"Grand Canyon Mather Campground\",\"location\":{\"lat\": 36.056472, \"lng\": -112.140728},\"id\":3}",
      "4": "{\"name\":\"Camping Paris Bois de Boulogne\",\"location\":{\"lat\": 48.868879, \"lng\": 2.234914},\"id\":4}"
    },
    "reservation": {
      "1": "{\"startDate\":\"2017-03-21\",\"endDate\":\"2017-03-23\",\"campgroundId\":1,\"customerId\":2,\"id\":1}",
      "2": "{\"startDate\":\"2017-03-25\",\"endDate\":\"2017-03-31\",\"campgroundId\":2,\"customerId\":3,\"id\":2}"
    },
    "customer": {
      "1": "{\"name\":\"Andy Van Den Heuvel\",\"username\":\"andy\",\"password\":\"$2a$10$1lmPRI0Xjd5fU8HGdPmDoOkZpIPJj2axcdJYIfc/3RUnBDDqQe31K\",\"email\":\"[email protected]\",\"id\":1}",
      "2": "{\"name\":\"Kenneth Van den Berghe\",\"username\":\"kenneth\",\"password\":\"$2a$10$H5wtnFvhxf8CPn66gEbPu.tki2WRpkplqvUV3yhQ049ugY8rHFSJi\",\"email\":\"[email protected]\",\"id\":2}",
      "3": "{\"name\":\"Claudiu Matei\",\"username\":\"claudiu\",\"password\":\"$2a$10$6b9jxIwb6y84gpq.ZU57YegRM4BWxHoXc.K/WwlEOJTa/9fO7cCta\",\"email\":\"[email protected]\",\"id\":3}"
    },
    "AccessToken": {},
    "ACL": {},
    "RoleMapping": {
      "1": "{\"principalType\":\"USER\",\"principalId\":\"1\",\"roleId\":1,\"id\":1}"
    },
    "Role": {
      "1": "{\"name\":\"admin\",\"created\":\"2017-02-21T06:07:25.571Z\",\"modified\":\"2017-02-21T06:07:25.571Z\",\"id\":1}"
    }
  }
}

Сега ще активираме нашето удостоверяване. За да направим това, трябва да добавим
bootscript. Създайте нов файлов сървър/boot/authentication.js със следното съдържание и след това рестартирайте сървъра си.

'use strict';

module.exports = function enableAuthentication(server) {
  server.enableAuth();
};

Удостоверяването вече е активирано, но всички крайни точки все още са публични, защото не сме конфигурирали никакво разрешение. Loopback използва списъци за „контрол на достъпа“ за това. Нека добавим някои правила тук.

Първо откажете всякакъв достъп на всички, lb acl:

? Select the model to apply the ACL entry to: (all existing models)
? 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

Сега позволете на всички да видят къмпингите, lb acl:

? Select the model to apply the ACL entry to: campground
? 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

Освен това позволете на всеки клиент да има собствена информация, lb acl:

? Select the model to apply the ACL entry to: customer
? Select the ACL scope: All methods and properties
? Select the access type: All (match all types)
? Select the role The user owning the object
? Select the permission to apply Explicitly grant access

И като последно правило, позволете на администраторите да правят и виждат всички,lb acl:

? Select the model to apply the ACL entry to: (all existing models)
? Select the ACL scope: All methods and properties
? Select the access type: All (match all types)
? Select the role other
? Enter the role name: admin
? Select the permission to apply Explicitly grant access

Стартирайте вашия сървър и отидете на http://localhost:3000/api/campgrounds. Като анонимен потребител все още мога да виждам всички къмпинги. Когато отида на http://localhost:3000/api/reservations, получавам 401 Изисква се оторизация.

Сега ще влезем като Кенет, за да видим неговите резервации. Отидете на http://localhost:3000/explorer/#!/customer/customer_login и влезте:

Идентификаторът на отговора е генериран токен за достъп. Вече можете да го копирате и да го зададете в заглавката, за да предоставите маркер за достъп за всички повиквания в API Explorer.

Или можете да добавите токена за достъп като параметър на заявка. Нека опитаме това.

  • Като Кенет мога да видя собствените си резервации: /api/customers/2/reservations?access_token=XMFN5GsykpxFokvWsXRYtKZidlJYKyClvak0KmEn87LisnFYSQ9TzmrBcz9GFrHv
  • Искането на резервациите на Клаудиу води до 401 неоторизиран: /api/customer/3/reservations?access_token=XMFN5GsykpxFokvWsXRYtKZidlJYKyClvak0KmEn87LisnFYSQ9TzmrBcz9GFrHv
  • Като Клаудиу виждам собствената си резервация: /api/customers/3/reservations?access_token=v51y2iZa1nkKTWC7s1yKELaIatfDJPVxcEEVa6FFIG4llZCGyZVbwR4plhfpYAxx
  • Но не мога да видя резервациите на Кенет: /api/customers/2/reservations?access_token=v51y2iZa1nkKTWC7s1yKELaIatfDJPVxcEEVa6FFIG4llZCGyZVbwR4plhfpYAxx
  • Като Анди мога да резервирам резервациите на Кенет: /api/customers/2/reservations?access_token=okxVkWcdoVzWb3WmCK9KkiuBArz1HOOHrIn1h2mOfa0kBzeUna1V9wFmFRe6BChe
  • А също и резервациите на Клаудиу: /api/customers/3/reservations?access_token=okxVkWcdoVzWb3WmCK9KkiuBArz1HOOHrIn1h2mOfa0kBzeUna1V9wFmFRe6BChe
  • Като Andy можете също да видите всички резервации: /api/reservations?access_token=okxVkWcdoVzWb3WmCK9KkiuBArz1HOOHrIn1h2mOfa0kBzeUna1V9wFmFRe6BChe

Логика на приложението

До този момент успяхме да изградим напълно функциониращ REST API, най-вече от генериране на код. Но по-напредналите приложения почти винаги ще се нуждаят от допълнителна логика на приложението.

Loopback ви позволява да добавяте отдалечени методи, отдалечени куки и куки за операции. Дистанционните куки и куките за работа са практически еднакви. Разликата е, че оперативните куки са дефинирани на по-високо ниво, докато отдалечените куки са по-специфични за крайна точка.

В нашия пример искаме да изпратим имейл за потвърждение, когато клиент е направил резервация. Loopback има наличен имейл конектор, базиран на Nodemailer

Отидете на server/datasources.json и добавете имейл конфигурацията. Използвах gmail за това:

{
  "reservationDS": {
    "name": "reservationDS",
    "localStorage": "",
    "file": "db.json",
    "connector": "memory"
  },
  "emailDS": {
    "name": "mail",
    "connector": "mail",
    "transports": [{
      "type": "SMTP",
      "host": "smtp.gmail.com",
      "secure": true,
      "port": 465,
      "auth": {
        "user": "YOUR_USER",
        "pass": "YOUR_PASSWORD"
      }
    }]
  }
}

Сега обвързваме източника на данни в server/models-config.js:

{
  "_meta": {
    "sources": [
      "loopback/common/models",
      "loopback/server/models",
      "../common/models",
      "./models"
    ],
    "mixins": [
      "loopback/common/mixins",
      "loopback/server/mixins",
      "../common/mixins",
      "./mixins"
    ]
  },
  "campground": {
    "dataSource": "reservationDS",
    "public": true
  },
  "reservation": {
    "dataSource": "reservationDS",
    "public": true
  },
  "customer": {
    "dataSource": "reservationDS",
    "public": true
  },
  "User": {
    "dataSource": "reservationDS",
    "public": false
  },
  "AccessToken": {
    "dataSource": "reservationDS",
    "public": false
  },
  "ACL": {
    "dataSource": "reservationDS",
    "public": false
  },
  "RoleMapping": {
    "dataSource": "reservationDS",
    "public": false
  },
  "Role": {
    "dataSource": "reservationDS",
    "public": false
  },
  "Email": {
    "dataSource": "emailDS"
  }
}

Отидете на server/models/reservation.js и добавете логиката за изпращане и имейл след запазване:

'use strict';

module.exports = function (Reservation) {
  Reservation.validate('startDate', dateValidator, {message: 'endDate should be after startDate'});
  function dateValidator(err) {
    if (this.startDate >= this.endDate) {
      err();
    }
  }

  Reservation.observe("after save", function (ctx, next) {   Reservation.app.models.Campground.findById(ctx.instance.campgroundId, function (err, campground) {
      Reservation.app.models.Email.send({
        to: '[email protected]',
        from: '[email protected]',
        subject: 'Thank you for your reservation at ' + campground.name,
        html: '<p>We confirm your reservation for <strong>' + campground.name + '</strong></p>'
      }, function (err, mail) {
        console.log('email sent!');
      });
    });
    next();
  });

};

Съхранение

Ако се интересувате от качване/изтегляне на файлове от вашия API, можете да използвате компонента за съхранение на Loopback. За целта трябва да инсталирате компонента за съхранение чрез NPM:

npm install loopback-component-storage --save

Точно както при имейлите, компонентът за съхранение се нарича източник на данни. Нека го добавим към server/datasources.json

{
  "reservationDS": {
    "name": "reservationDS",
    "localStorage": "",
    "file": "db.json",
    "connector": "memory"
  },
  "emailDS": {
    "name": "mail",
    "connector": "mail",
    "transports": [{
      "type": "SMTP",
      "host": "smtp.gmail.com",
      "secure": true,
      "port": 465,
      "auth": {
        "user": "YOUR_USER",
        "pass": "YOUR_PASSWORD"
      }
    }]
  },
  "photos": {
    "name": "photos",
    "connector": "loopback-component-storage",
    "provider": "filesystem",
    "root": "./server/files"
  }
}

Ние използваме нашата локална файлова система като доставчик тук, но компонентът за съхранение използва pkgcloud за поддръжка на множество облачни доставчици (Amazon, Azure, Google, HP, Openstack, Rackspace)

Loopback съхранява файлове в контейнери. Трябва да направим модел на контейнер, за да можем да създадем контейнер за нашите снимки, lb модел:

? Enter the model name: container
? Select the data-source to attach container to: photos (loopback-component-storage)
? Select model's base class Model
? Expose container via the REST API? Yes
? Custom plural form (used to build REST URL): 
? Common model or server only? server
Let's add some container properties now.

Enter an empty property name when done.
? Property name:

Създайте папката server/files/photos, за да можем да качим няколко снимки в нея и да стартираме вашия сървър. Когато отидете в API Explorer, можете да видите крайната точка /containers, но все още не сме създали никакви контейнери. За тази част ще използваме curl.

Създайте контейнера „снимки“:

curl -X GET --header 'Accept: application/json' 'http://localhost:3000/api/containers/photos'

Качете в контейнера за снимки:

curl -F "[email protected]" http://localhost:3000/api/containers/photos/upload

Изтеглете от контейнера „снимки“:

http://localhost:3000/api/containers/photos/download/image.jpg

Тестване

Ние сме почти готови, но искаме да сме сигурни, че можем да тестваме нашите крайни точки. За това ще използваме mocha, chai и chai-http.

Ако нямате мока на вашата машина. Инсталирайте го глобално чрез npm

npm install -g mocha

След това инсталирайте chai и chai-http за проекта:

npm install chai chai-http --save-dev

Вече можем да напишем тест на test/campground.js. Не съм написал пълния набор от тестове тук, само няколко теста, за да схванете идеята. chai ще се увери, че сървърът е стартиран, преди да направим заявката, и спря след теста.

'use strict';

var chai = require('chai');
var chaiHttp = require('chai-http');
var server = require('../server/server');
var should = chai.should();

chai.use(chaiHttp);

describe('Campgrounds', function() {
  it('should show all campgrounds on GET /api/campgrounds', function(done) {
    chai.request(server)
      .get('/api/campgrounds')
      .end(function(err, res) {
        res.should.have.status(200);
        res.body.should.have.lengthOf(4);
        done();
      });
  });

  it('should show only the names of the campgrounds on GET /api/campgrounds?filter[fields][name]=true', function(done) {
    chai.request(server)
      .get('/api/campgrounds?filter[fields][name]=true')
      .end(function(err, res) {
        res.should.have.status(200);
        res.body[0].should.have.property('name');
        res.body[0].should.not.have.property('id');
        done();
      });
  });

  it('should show the first 2 campgrounds on GET /api/campgrounds?filter[limit]=2', function(done) {
    chai.request(server)
      .get('/api/campgrounds?filter[limit]=2')
      .end(function(err, res) {
        res.should.have.status(200);
        res.body.should.have.lengthOf(2);
        res.body[0].name.should.equal('Salt Lake City KOA');
        res.body[1].name.should.equal('Gouldings Campground');
        done();
      });
  });

  it('should show the last 2 campgrounds on GET /api/campgrounds?filter[skip]=2&filter[limit]=2', function(done) {
    chai.request(server)
      .get('/api/campgrounds?filter[skip]=2&filter[limit]=2')
      .end(function(err, res) {
        res.should.have.status(200);
        res.body.should.have.lengthOf(2);
        res.body[0].name.should.equal('Grand Canyon Mather Campground');
        res.body[1].name.should.equal('Camping Paris Bois de Boulogne');
        done();
      });
  });
});

Изпълнете командата mocha сега и трябва да видите, че всички тестове преминават:

Добре, почти сме готови. Последна спирка: внедряване в производство.

Разгръщане

За да преминем към производство, имаме нужда от някаква „специфична за околната среда конфигурация“.

Loopback има конвенции за именуване за това. От съображения за сигурност не искаме да показваме API Explorer, когато работи в производствена среда. Създайте файл с име /server/component-config.prod.json

{
  "loopback-component-explorer": null
}

Също така не искаме да работим срещу база данни в паметта. Тук ще преминем към mongoDB. Ще трябва да инсталираме MongoDB Connector за него:

npm install loopback-connector-mongodb --save

Ще използвам MongoDB, хостван от MLab. Можете да се регистрирате и да създадете безплатна пясъчна среда и тук.

  • Създайте база данни „резервации“
  • Идентификационните данни на потребителското име, които сте използвали за регистрация в MLab, не се използват за свързване във вашето приложение, уверете се, че сте създали потребител на база данни тук:

Създайте нов файл с име server/datasources.prod.json и добавете настройките на mongodb:

{
  "reservationDS": {
    "host": "YOUR_HOST",
    "port": 0,
    "url":  false,
    "database": "reservations",
    "name": "reservations",
    "connector": "mongodb",
    "user": "YOUR_USERNAME",
    "password": "YOUR_PASSWORD"
  }
}

Забележете, че тук използваме модела за именуване componenet-config.env.json и datasources.env.json. Loopback използва NODE_ENV, за да реши каква конфигурация трябва да се зареди. Нека променим нашата среда на прод.

export NODE_ENV="prod"

Loopback вече ще използва нашата нова конфигурация. Нашият изследовател е деактивиран и все още можем да използваме are api, този път чрез MongoDB:

http://localhost:3000/api/campgrounds

Тъй като сега работим върху mongoDB, вече нямаме налични тестови данни. Нека създадем „къмпинг“ за колекция и когато щракнете върху колекцията, можете да добавите нов документ.

Можете да направите всичко това в уеб интерфейса на mLab. например:

{
    "name": "Salt Lake City KOA",
    "location":{
        "lat": 40.772112, 
        "lng": -111.932165
    }
}

Когато създадете документа и отидете на http://localhost:3000/api/campgrounds и трябва да видите новосъздадения.

Програмен код

https://github.com/optis/loopback-rest-api

Ресурси

http://loopback.io
https://github.com/strongloop/loopback-example-access-control