Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Node.js
Code

Создание API REST с помощью AWS SimpleDB и Node.js

by
Difficulty:IntermediateLength:LongLanguages:

Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)

SimpleDB - это удаленная база данных, прелагаемая Amazon Web Services (AWS). Мир хранилищ данных обычно делится на SQL и NoSQL, основываясь на использовании (или неприменении) языка SQL. Хранилища данных NoSQL обычно основаны на более простой настройке ключа / значения. SimpleDB ограничивает эту строку - это хранилище ключей / значений и также может использовать вариант SQL для извлечения. Большинство языков SQL основаны на схеме, в которой указаны строки и столбцы данных, но SimpleDB - это база данных без схемы, создающая очень гибкий хранилище данных.

В модели базы данных SimpleDB у вас есть элементы, атрибуты и значения. Каждая строка в базе данных является элементом и может быть идентифицирована уникальным и назначаемым именем элемента. Каждый элемент может иметь до 256 пар атрибутов и значений. Неожиданным аспектом SimpleDB является то, что атрибут может содержать более одной пары на элемент. Я думаю, что лучший способ подумать о SimpleDB - подумать о электронной таблице, но вместо каждого пересечения столбца / строки, представляющего одно значение, он представляет собой массив значений.

Grid illustrating Item Name Attribute Value relationship

Эта диаграмма представляет два элемента, хранящихся в домене SimpleDB. Термин домен аналогичен «таблице» в других базах данных.

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

Остальные четыре столбца (домашние животные, автомобили, мебель и телефоны) представляют собой атрибуты, которые в настоящее время находятся в этом домене - вы не ограничены этим, поэтому каждый элемент может иметь совершенно уникальный набор атрибутов. В этих данных атрибут pets на элементе personInventory1 имеет три пары; выраженный в JSON, он будет выглядеть примерно так:

С другой стороны, элемент personInventory2 имеет только одну пару:

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

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

Не паникуйте: это не так плохо, как кажется по нескольким причинам. С SimpleDB согласованность не обещана, но обычно она довольно хороша и быстро достигает всех узлов из моего опыта. Проектирование вокруг этого также не так сложно - обычно вы пытаетесь избежать немедленного чтения записи, которую вы только что написали. Наконец, SimpleDB имеет возможность выполнять последовательные чтения, но они медленнее и могут потреблять больше ресурсов. Если ваше приложение требует последовательного чтения каждый раз, вам может потребоваться пересмотреть использование SimpleDB в качестве хранилища данных, но для многих приложений это может быть вполне приемлимым.

С другой стороны, распределенный характер также предоставляет SimpleDB несколько преимуществ, которые хорошо сочетаются со средой Node.js. Поскольку у вас нет одного сервера, отвечающего на ваши запросы, вам не нужно беспокоиться о нагрузке на сервисы, и вы можете добиться хорошей производительности, сделав много параллельных запросов к SimpleDB. Параллельные и асинхронные запросы - это то, с чем легко справляется Node.js.

В отличие от многих услуг AWS, для управления SimpleDB нет консоли Amazon. К счастью, есть хорошая консоль управления в браузере в виде плагина Google Chrome, SdbNavigator. В SdbNavigator вы можете добавлять или удалять домены, вставлять, обновлять и удалять элементы, изменять атрибуты и выполнять запросы.

AWS SDK

Теперь, когда мы узнали о службе SimpleDB, давайте начнем писать наш сервер REST. Во-первых, нам нужно установить AWS SDK. Этот SDK обрабатывает не только SimpleDB, но и все службы AWS, поэтому вы можете уже включать его в файл package.json. Чтобы установить SDK, запустите в командной строке:

Чтобы использовать SimpleDB, вам также необходимо получить свои учетные данные AWS, которые включают ключ доступа и секретный ключ. SimpleDB - это услуга с «оплатой по мере необходимости», но AWS в настоящее время включает в себя щедрое бесплатное предложение для SimpleDB.

Предупреждение: как и с любым сервисом pay-as-you-go, имейте в виду, что можно писать код, который может набирать большие счета, поэтому вы захотите следить за своим использованием и хранить свои учетные данные в приватном режиме и безопасно.

После того, как вы установили AWS SDK и приобрели свои учетные данные, вам нужно настроить SimpleDB в своем коде. В этом примере мы будем использовать учетные данные AWS, хранящиеся в файле JSON в вашем домашнем каталоге. Во-первых, вам нужно будет включить модуль SDK, создать объект AWS и, наконец, настроить свой интерфейс SimpleDB.

Обратите внимание, что мы используем конкретный ендпоинт и регион. Каждый центр данных полностью независим, поэтому, если вы создадите Домен с именем «mysuperawesomedata» в Северной Вирджинии, он не будет реплицироваться и не находиться в центре данных Сан-Паулу, например.

Объект SimpleDB, созданный с помощью new aws.SimpleDB, будет содержать все необходимые методы для взаимодействия с SimpleDB. AWS SDK для SimpleDB имеет только несколько методов:

Групповые операции

  • batchDeleteAttributes
  • batchPutAttributes

Управление доменами и информация

  • CreateDomain
  • deleteDomain
  • domainMetadata
  • listDomains

Манипуляция Item / Attribute

  • deleteAttributes
  • GetAttributes
  • putAttributes

Запросы

  • select

В этом уроке мы будем иметь дело только с манипуляцией Item / Attribute и Querying; в то время как другие категории полезны, многие приложения не будут им пользоваться.

Тестовые данные

Используя SdbNavigator, введите ключи доступа и безопасности в инструмент, выберите «US-East» и нажмите «Подключиться».

Connection UI to SdbNavigator

Как только вы успешно подключитесь, давайте создадим домен для тестирования. Нажмите Add domain.

Adding a domain via the SdbNavigator

Затем введите доменное имя «sdb-rest-tut» и нажмите «ОК».

Entering the name of the new domain

Теперь, когда вы создали домен, давайте введем некоторые тестовые данные. Нажмите Add property и добавьте свойство «colors». Как правило, я обычно называю свойства во множественном числе, чтобы отражать многозначную природу SimpleDB.

Adding a property name to the record

Наконец, мы нажмем Add record, чтобы создать наш первый элемент SimpleDB. В столбце ItemName() введите уникальное имя элемента. Причуда SdbNavigator заключается в том, что по умолчанию он будет принимать только одно значение для каждого элемента, но это скрывает тот факт, что свойство может содержать несколько значений. Чтобы ввести несколько значений, щелкните S по правому краю столбца свойств.

Entering a unique item name

В новом окне выберите Array, чтобы ввести несколько значений. В столбце Value введите «red», а затем нажмите Add value и введите «blue».

Entering the data type of the item

Наконец, нажмите Update, чтобы сохранить изменения в этой строке.

Updating the data type of the item

Теперь, когда мы ввели некоторые тестовые данные, сделаем первый запрос SimpleDB от Node. Мы просто получим все в Домене, который на данный момент будет всего лишь одной строкой.

Ответ будет отправлен на консоль. Вот ответ, поясненный для объяснения:

Сервер REST

Поскольку мы будем создавать REST-сервер, который хранит данные в SimpleDB, важно понять, что делает сервер REST. REST означает REpresentational State Transfer. Сервер REST - это просто сервер, который использует стандартные HTTP-механизмы в качестве интерфейса для ваших данных. Часто REST используется для связи между серверами, но вы можете использовать REST-серверы с клиентом через библиотеки JavaScript, такие как jQuery или Angular. Однако, как правило, конечный пользователь не будет взаимодействовать напрямую с сервером REST.

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

В этом уроке мы будем создавать базовые функции CRUD + L, то есть Create, Read, Update, Delete и List. Если вы думаете об этом, вы можете разбить большинство приложений на CRUD + L. С помощью REST вы будете использовать ограниченное количество путей и несколько HTTP-методов или глаголов для создания интуитивно понятного API. Большинство разработчиков знакомы с некоторыми из HTTP-глаголов, а именно GET и POST, поскольку они чаще всего используются в веб-приложениях, но есть несколько других.

Operation HTTP-глагол
Create POST
Read GET
Update PUT
Delete DELETE
List GET

Обратите внимание, что Read и List используют один и тот же глагол; мы будем использовать несколько разные пути, чтобы различать их. Мы используем POST для представления Create, поскольку создание не считается idempotent. Idempotent означает, что несколько идентичных вызовов будут иметь тот же результат для пользователя и ваших данных, поэтому обновление (aka PUT) будет считаться идемпотентным.

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

Operation HTTP-глагол Path
Create POST /inventory
Read GET /inventory/1234
Update PUT /inventory/1234
/inventory/1234 DELETE /inventory/1234
List GET / инвентарь

1234 является заполнителем для идентификатора человека (ID) - обратите внимание, что в «create» и «list» не имеют идентификатора. В случае создания будет создан идентификатор, и со списком мы получим все имена, поэтому нам не нужен конкретный идентификатор.

Создание сервера

Чтобы начать работу, давайте установим Express, фреймворка для HTTP-сервера Node.js:

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

Body-parser имеет несколько различных параметров для синтаксического анализа тела HTTP-запроса. Мы будем использовать метод json() для удобочитаемости, но переход на другой метод - это просто замена метода на объект bodyParser. Нам нужен  bodyParser только для методов создания и обновления, поэтому мы можем просто включить его в эти конкретные маршруты.

Create

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

SimpleDB ожидает, что атрибуты будут находиться в формате пары имя/значение атрибута:

Ваш сервер, безусловно, может просто принять и передать значения в этом формате непосредственно в SimpleDB, но он несовместим с тем, как часто структурируются данные, и это сложная концепция, с которой можно работать. Мы будем использовать более интуитивную структуру данных, массив объектов/значений:

Вот базовый сервер на основе Express с операцией create:

Давайте запустим ваш сервер и попробуем его. Отличный способ взаимодействия с сервером REST - использовать инструмент cURL. Этот инструмент позволяет вам сделать HTTP-запрос с любым глаголом прямо из командной строки. Чтобы попробовать создать элемент на нашем сервере REST, нам нужно активировать несколько дополнительных опций:

Option Purpose
-H Добавить строку в заголовок HTTP
-X Определите, какой глагол будет использоваться
-d Данные, отправляемые в тело запроса HTTP

После выполнения команды вы увидите ответ JSON с вашим новым созданным именем элемента или идентификатором. Если вы переключитесь на SdbNavigator, вы увидите новые данные при запросе всех элементов.

Read

Теперь давайте построим базовую функцию для чтения элемента из SimpleDB. Для этого нам не нужно выполнять запрос, так как мы будем получать itemName или ID с пути запроса. Мы можем выполнить запрос getAttributes с этим ItemName или ID.

Если бы мы остановились здесь, у нас была бы функциональная, но не очень дружелюбная форма наших данных. Давайте преобразуем массив Name/Value в ту же форму, которую мы используем, чтобы принимать данные (атрибут: массив значений). Для этого нам нужно пройти через каждую пару имя/значение и добавить его в новый массив для каждого уникального имени.

Наконец, давайте добавим itemName и вернем результаты.

Чтобы проверить это, нам нужно снова использовать curl. Попробуйте заменить [cuid] на itemName или ID, возвращенный из нашего примера создания элемента ранее в этом уроке.

Обратите внимание, что мы используем опцию -D. Это дамп HTTP-заголовка, чтобы мы могли видеть код ответа.

Другим аспектом REST является использование ваших кодов ответа по назначению. В текущем примере, если вы поставляете несуществующий идентификатор для завивки, вышеупомянутый сервер будет аварийно завершен, потому что вы пытаетесь использовать forEach для несуществующего массива. Нам нужно учесть это и вернуть значимый код ответа HTTP, указывающий, что элемент не найден.

Чтобы предотвратить ошибку, мы должны проверить наличие переменной awsResp.Attributes. Если этого не существует, давайте установим код состояния 404 и завершим http-запрос. Если он существует, мы можем обслуживать ответ с атрибутами.

Попробуйте использовать новый код и несуществующий идентификатор, и вы увидите, что сервер возвращает 404.

Теперь, когда мы знаем, как использовать status для изменения значения, мы также должны обновить, как мы реагируем на POST / create. Хотя ответ 200 технически корректен, так как это означает «ОК», более проницательный код ответа будет 201, что означает «создан». Чтобы внести это изменение, мы добавим его в метод состояния перед отправкой.

Update

Обновление обычно является самой сложной операцией для любой системы, и этот сервер REST не является исключением.

Природа SimpleDB делает эту операцию еще более сложной. В случае сервера REST обновление - это место, где вы заменяете всю часть хранимых данных; SimpleDB, с другой стороны, представляет отдельные пары атрибут / значение под элементом itemName.

Чтобы позволить обновлению представлять единый фрагмент данных, а не набор пар имя / значение, нам нужно определить схему для целей нашего кода (хотя SimpleDB не нуждается в ней). Не беспокойтесь, если это сейчас неясно - продолжайте читать, и я проиллюстрирую это требование.

По сравнению со многими другими системами баз данных наша схема будет очень простой: просто определенный массив атрибутов. Для нашего примера у нас есть четыре поля, на которых мы сосредоточились: petscarsfurniture, и phones:

С SimpleDB вы не можете хранить пустую пару атрибут / значение, а SimpleDB не имеет понятия отдельных элементов, поэтому мы будем предполагать, что если SimpleDB не возвращает значение, оно не существует. Аналогичным образом, если мы попытаемся обновить элемент SimpleDB пустым парой атрибутов / значений, он будет игнорировать эти данные. Возьмем, к примеру, эти данные:

Логически, мы знаем, что cars, являющиеся пустым массивом, не должны иметь никаких значений, а pets должны иметь два значения, но как насчет phones и furniture? Что вы с ними делаете? Вот как мы переводим этот запрос на обновление для работы с SimpleDB:

  • Поместите атрибут pet со значением cat.
  • Поместите атрибут pet со значением dog.
  • Удалить атрибуты для cars.
  • Удалить атрибуты для phones.
  • Удалить атрибуты для furniture.

Без какой-либо схемы, которая, по крайней мере, определяет атрибуты, мы не знали, что phones и furniture необходимо удалить. К счастью, мы можем консолидировать эту операцию обновления в два запроса SimpleDB вместо пяти: один для размещения атрибутов и один для удаления атрибутов. Это хорошее время, чтобы вытащить код из функции post / create, которая преобразует объект attribute / array of values в массив пар атрибут / значение.

Мы также сделаем важное изменение для функции create. Мы добавим новый атрибут/значение ко всем элементам. Этот атрибут не будет добавлен в схему и будет доступен только для чтения.

Мы добавим атрибут created и установим значение в 1. С SimpleDB существует ограниченная возможность проверить, существует ли элемент до добавления атрибутов и значений. В каждом запросе putAttributes вы можете проверить значение и существование одного атрибута - в нашем случае мы будем использовать created и проверять значение 1. Хотя это может показаться странным обходным решением, оно обеспечивает очень важную безопасность, чтобы предотвратить операцию обновления из-за возможности создавать новые элементы с произвольным идентификатором.

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

Помните, поскольку SimpleDB распространяется, нет причин последовательно помещать наши атрибуты, а затем удалять. Мы будем использовать функцию async.parallel для запуска этих двух операций и получения обратного вызова, когда оба завершатся. Ответы формы AWS putAttributes и deleteAttributes не предоставляют важной информации, поэтому мы просто отправим пустой ответ с кодом состояния 200, если ошибок нет.

Чтобы принять это за спину, давайте обновим ранее созданную запись. На этот раз инвентарь включает только «собаку», удалив все остальные предметы. Опять же, с помощью cURL, запустите команду, заменив [cuid] на один из ваших идентификаторов элементов.

Delete

У SimpleDB нет понятия удаления элемента, но он может удалить атрибуты, как указано выше. Чтобы удалить элемент, нам нужно удалить все атрибуты, и элемент перестанет быть.

Поскольку мы определили список атрибутов в нашей схеме, мы будем использовать вызов deleteAttributes для удаления всех этих атрибутов, а также атрибута created. Согласно нашему плану, эта операция будет проходить по тому же пути, что и Update, но с использованием verb  DELETE.

List

Последний из глаголов REST - это list. Для выполнения операции списка мы будем использовать команду select и SQL-подобный язык запросов. Наша функция списка будет barebones, но будет служить хорошей основой для более сложного поиска позже. Мы сделаем очень простой запрос:

Когда мы столкнулись с операцией get/read, ответ от SimpleDB не очень полезен, поскольку он ориентирован на пары атрибут/значение. Чтобы избежать повторения, мы реорганизуем часть операции get/read в отдельную функцию и используем ее здесь. Пока мы в нем, мы также отфильтровываем атрибут created (как он будет отображаться в операции get).

С помощью операции select SimpleDB возвращает значения в массиве Items. Каждый элемент представлен объектом, который содержит имя элемента (как просто Name) и пары атрибут / значение.

Чтобы упростить этот ответ, давайте вернем все в одном объекте. Сначала мы преобразуем пары атрибут / значение в массив атрибутов / значений, как это было в операции read / get, и затем мы можем добавить itemName как идентификатор свойства.

Чтобы увидеть наши результаты, мы можем использовать curl:

Валидация

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

На данный момент мы хотим убедиться, что пользователь не может ничего представить, кроме того, что находится в схеме. Оглядываясь на код, написанный для update / put, forEaching по схеме предотвратит добавление несанкционированных атрибутов, поэтому нам просто нужно применить что-то похожее на нашу операцию create / post. В этом случае мы будем фильтровать пары атрибут/значение, исключая любые атрибуты вне схемы.

В вашем боевом коде вам, скорее всего, понадобится более надежная система проверки. Я бы предложил интегрировать валидатор схемы JSON, например ajv, и создать middleware, которое находится между bodyParser и вашей функцией маршрута при создании и обновлении.

Следующие шаги

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

  • Аутентификация
  • Пагинация
  • Сложные операции со списком/запросами
  • Дополнительные выходные форматы (xml, csv и т.д.)

Эта основа для сервера REST, работающего на SimpleDB, позволяет добавлять middleware и дополнительную логику для создания каркаса для вашего приложения.

Окончательный код сервера доступен в simpledb-rest-api на GitHub.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.