machinelearningmastery.ru

Машинное обучение, нейронные сети, искусственный интеллект
Header decor

Home

Простой REST API с выразительным чаем | Часть третья

Дата публикации Oct 3, 2019

Добро пожаловать в нашу серию уроковВыразительный чай, В этом уроке мы продолжим работу над бэкэнд-приложением todo, начиная с приложения в оперативной памяти, чтобы использовать службу базы данных. Для этого урока мы выбралиMongoDBкоторый является одним из самых популярныхNon-SQLдвижки базы данных, мы выбралиМангустакак нашORMопределения системы и модели, идокер, что поможет нам легко развернуть наше приложение в нашей локальной системе.

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

Нам не нужны экспертные знания поMongoDB,докер, а такжеМангустапоскольку это всего лишь небольшой урок, объясняющий, как мы можем использовать базы данных в наших приложениях; следовательно, этот учебник может быть легко понятен и может заинтересовать эти технологии; Тем не менее, этот учебник принесет некоторые изES6(и далее) функции, которые потребуют знаний в этой области.

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

Начиная

Dockerize наше приложение.

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

Основная идея «dockerize» нашего приложения состоит в том, чтобы поддерживать изолированную среду, в которой мы уверены, что наше приложение будет работать на любой машине в разных операционных системах (где поддерживается Docker) и включать наши службы, которые в этом нуждаются. В этом случае MongoDB.

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

Давайте начнем создавать файл docker-compose, чтобы указать, что нам нужно для нашего приложения dockerize. В корневой папке создайте файл с именемдокер-compose.ymlи скопируйте и вставьте следующий код.

version: "3"
services:
todo:
image: "node:10-alpine"
user: "node"
working_dir: "/home/node/app"
environment:
- NODE_ENV=development
volumes:
- ./:/home/node/app
ports:
- "3000:8080"
command: "./docker-runner.sh"

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

И теперь в терминале нам нужно создать нашdocker-runner.shфайл со следующими командами:

$ touch docker-runner.sh
$ chmod +x docker-runner.sh

И скопируйте и вставьте следующие строки:

#!/usr/bin/env sh
set -e
npm start

После того, как у нас есть сценарий docker-compose и docker-runner, нам нужно протестировать его, выполнив командуdocker-compose upВ корневой папке проекта вы увидите нечто похожее на следующее изображение:

Теперь давайте перейдем в наш браузер и перейдем по URL-адресуhttp://localhost:8080/todo/А также…

Вы увидите, что наш браузер не отвечает на наш сервер, даже если он работает правильно; в этот момент вы, вероятно, если у вас нет опыта в докере, спрашивают вас, делаете ли вы что-то не так. ОтветНЕПомните, что я говорил вам в начале, теперь наше приложение - это контейнер, который работает как независимая машина (даже если работает на нашем локальном компьютере), тогда как мы можем протестировать наш сервер? Ответ находится в нашем файле docker-compose, если вы посмотрите на следующую строку:

ports:
- "3000:8080"

Вы увидите, что мы перенаправляем контейнерный порт8080на нашу локальную машину в порту3000тогда давайте попробуем:http://localhost:3000/todoА также…

Теперь наше приложение работает в док-контейнере; Вы можете пойти и протестировать все конечные точки, которые мы работали над учебником второй части, используя Postman, изменив порт 8080 на 3000.

Получение MongoDB.

Добавить образ монго в наш проект относительно просто, требуется добавить несколько новых строк в наш файл конфигурации docker-compose следующим образом:

version: "3"
services:
todo:
image: "node:10-alpine"
user: "node"
working_dir: "/home/node/app"
environment:
- NODE_ENV=development
volumes:
- ./:/home/node/app
ports:
- "3000:8080"
command: "./docker-runner.sh"

mongodb:
image: "mongo"
ports:
- "27017:27017"
volumes:
- "./mongodb-data:/data/db"

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

Есть два способа сделать оба контейнера «видимыми», мы можем использовать сеть или связать контейнеры. Мы будем использовать ссылки на контейнер, что является более естественным способом, и это работает для наших целей Давайте изменим конфигурационный файл docker-container следующим образом:

version: "3"
services:
todo:
image: "node:10-alpine"
user: "node"
working_dir: "/home/node/app"
environment:
- NODE_ENV=development
- MONGO_URL=mongodb://mongodb/todo
volumes:
- ./:/home/node/app
ports:
- "3000:8080"
command: "./docker-runner.sh"
links:
- mongodb
depends_on:
- mongodb
restart: always
mongodb:
image: "mongo"
ports:
- "27017:27017"
volumes:
- "./mongodb-data:/data/db"

Теперь пришло время попробовать эти новые изменения на нашей локальной машине, нам нужно остановить запущенные в данный момент контейнеры нажатиемctrl+cи дождаться полной остановки контейнера; возможно иногда используюctrl+cне работает правильно, в этом случае вы можете использовать командуdocker-compose stop,

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

Теперь пришло время перейти к забавной части.

Вот иди… Мангуст

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

Подsrcпапка создать новую папку с именемpluginsИ создайте файл с именем database.ts и установите Mongoose, чтобы добавить его в наш проект.

$ npm i --save mongoose

И добавьте следующий контент вdatabase.tsфайл:

import * as mongoose from "mongoose"export default async function databaseInitialize() {
await mongoose.connect(process.env.MONGO_URL, {
useCreateIndex: true,
useNewUrlParser: true
})
}

После создания файла серверу необходимо зарегистрировать плагин, как мы это сделали сbody-parserиспользуяPlugдекоратор. Сначала импортируйте файл базы данных, который мы создали в файле main.ts, какimport databaseInitialize from “./src/plugins/database"и добавьте следующую строку надbody-parserплагины:@Plug(BOOT_STAGES.INITIALIZE_MIDDLEWARES, “Database Config", databaseInitialize, true); дождитесь автоматического обновления приложения, и в журнале терминала вы должны увидеть запись, подобную следующей, что означает, что все работает нормально, и приложение теперь подключено к MongoDB.

Теперь, когда наше приложение подключено к базе данных, оно должно знать, какова модель для представления элементов задач. Для этого давайте начнем создавать папкуmodelsподsrcпапку и создайте файлtodo.ts,

import { model, Schema } from "mongoose";export const TodoSchema = new Schema(
{
title: { type: String, required: true },
isFinished: { type: Boolean, default: false }
},
{ timestamp: true }
);export const Todo = model("Todo", TodoSchema);

Приведенный выше код определяет схему модели Todo и определяет свойства и тип, который будет возвращен или принят, есть только два свойства,titleкак строковое значение, и оно будет необходимо при сохранении, иisFinishedкак логические значения со значением по умолчанию как false.

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

import * as mongoose from "mongoose"export default async function databaseInitialize() {
await mongoose.connect(process.env.MONGO_URL, {
useCreateIndex: true,
useNewUrlParser: true
})require("../models/todo")
}

Boom !! Наша модель и база данных настроены и готовы к использованию…

Реализация модели.

С этой части и тогда все будет проще, так как мы уже настроилиMongoDBсервер, и мы создалимодельначать получать данные из базы данных. Теперь мы будем внедрять модель в нашемTodo Controllerи измените конечные точки, чтобы получить данные из базы данных.

Это путешествие начинается с неотъемлемой части всего; нам нужно импортировать модель в наш контроллер со следующей строкой:

import { Todo } from "../../../models/todo";

Получаю все Тодо.

После импорта модели в контроллер мы изменим следующую конечную точку:

// From this@Get("/")
async index(req, res) {
res.json(todos)
}// To this code:@Get("/")
async index(req, res) {
res.json(await Todo.find())
}

затем откройте Почтальон и проверьте это, и вы должны получить пустой массив в ответе, не забудьте использовать порт 3000 вместо 8080 какhttp://localhost:3000/todo,

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

Создание Todo.

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

// From this implementation
@Post("/")
createTodo(req, res) {
const todo: ITodo = {
id: max(map(todos, t => t.id)) + 1,
title: req.body.title,
isFinished: false
}todos.push(todo)
res.json(todo)
}// To this one
@Post("/")
async createTodo(req, res) {
try {
const todo = new Todo({
title: req.body.title
})await todo.save()
res.json(todo)
} catch (e) {
res.status(400).json(e)
}
}

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

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

Наконец, если вы проверите это, чтобы получить все Todos ...

Получение Тодо.

Пока что последняя часть кажется легкой; на данный момент у нас есть конечная точка для получения всех данных и одна для создания новых Todos. Эта часть не будет проблематичной, чем две другие секции. Чтобы получить элемент todo из базы данных, когдапарыtodoIdявляется частью URL, как показано в следующем окне:

// From this
@Param("todoId")
getTodoItem(req, res, next, todoId) {
req.selectedTodoItem = find(todos, { id: parseInt(todoId, 10) })
if (!req.selectedTodoItem)
return next(new BadRequestException("Maybe you should look in another castle"))
next()
}// To this
@Param("todoId")
async getTodoItem(req, res, next, todoId) {
try {
req.selectedTodoItem = await Todo.findById(todoId)
if (!req.selectedTodoItem)
return next(new BadRequestException("Maybe you should look in another castle"))
next()
} catch (e) {
return next(new BadRequestException("Maybe you should look in another castle"))
}
}

Здесь мы снова добавили слово «асинхронный», чтобы получить чистый ответ в одну строку, и это все; чтобы получитьСделатьпункт мы изменимидентификатор ключаиз части URL и используйте объект id MongoDB, который вы можете получить при извлечении всех данных.

Редактировать Todo.

На данный момент, вероятно, вы спросите это, это просто?

Ну, здесь есть более шаткие… шаткие вещи, и да, эта часть тоже проста, просто требуется изменитьСтавитьизаплатаконечные точки теперь следующие за следующим кодом:

// From
@Put("/:todoId")
editTodo(req, res) {
const { title } = req.body
req.selectedTodoItem.title = title
res.json(req.selectedTodoItem)
}// To
@Put("/:todoId")
async editTodo(req, res) {
const { title } = req.body
req.selectedTodoItem.title = title
res.json(await req.selectedTodoItem.save())
}

использовать в качестве следующего изображения

Теперь очередь зазаплатаконечная точка, которая переместит наш todo для завершения статуса, шаги должны быть такими же, как top, как вы увидите в следующем блоке:

// From
@Patch("/:todoId/complete")
completeTodo(req, res) {
req.selectedTodoItem.isFinished = true
res.json(req.selectedTodoItem)
}// To
@Patch("/:todoId/complete")
async completeTodo(req, res) {
req.selectedTodoItem.isFinished = true
res.json(await req.selectedTodoItem.save())
}

после изящного перезапуска нашего приложения мы можем проверить следующее изображение:

Удалить Todo.

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

Это будет быстро, поэтому, пожалуйста, следуйте следующему блоку:

// From
@Delete("/:todoId")
deleteTodo(req, res) {
const deletedTodos = remove(todos, { id: req.selectedTodoItem.id })
res.json(deletedTodos)
}// To
@Delete("/:todoId")
async deleteTodo(req, res) {
res.json(await req.selectedTodoItem.remove())
}

Мы можем проверить это с помощью почтальона ...

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

Да так просто, как это ...

Убирайся

Теперь мы перемещаем всю логику в памяти, чтобы быть в базе данных и сделатьCRUDв коллекции todo вMongoDBВажно знать, что теперь нам нужно выполнить некоторую очистку в нашем коде, нам нужно удалить следующие строки импорта:

import { ITodo, todos } from "../data/todos"
import { find, max, map, remove } from "lodash"

Нам не нужно больше данных иlodashбиблиотека. Кроме того, вы можете удалить папку в каталоге модуля todo, чтобы поддерживать код в чистоте и не иметь никакого мертвого кода в нашем проекте.

Выводы.

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

Вероятно, для большинства из вас это конец пути, потому что мы сделали это, функционально, полностью работоспособно.REST APIс помощьюВыразительный чайэто была основная цель, и мы завершили этот урок, однако, будет новый урок и последний урок из этой серии, где я коснусь, главным образом, внедрения зависимостей и типирования. Некоторые приемы, чтобы лучше работать с Expressive Tea.

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

Оригинальная статья

Footer decor

© machinelearningmastery.ru | Ссылки на оригиналы и авторов сохранены. | map