Поиск по сайту:

Как построить сервер API?


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

Что такое сервер API и как он работает?

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

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

Это позволяет клиентам безопасно получать доступ к вашим данным через HTTP/HTTPS. Поскольку сервер API принадлежит вам и контролируется вами, это соединение может быть защищено проще. Хотя вам все равно потребуется некоторая форма аутентификации, чтобы убедиться, что пользователи вошли в систему как те, за кого они себя выдают.

Сервер API не предназначен для выполнения тяжелой работы на вашем веб-сайте. Для большей части статического контента лучше использовать традиционный веб-сервер, такой как NGINX, который будет гораздо более производительным. Например, вы будете обслуживать index.html и bundle.js с помощью своего сервера NGINX, который клиент распаковывает и запускает. Затем приложение JavaScript на стороне клиента отправит запрос на сервер API, который обработает его оттуда.

Вы можете создавать API-серверы с любым языком — все, что вам нужно, — это возможность прослушивать HTTP-запросы и отвечать на них, а также возможность подключаться к базе данных, обе из которых имеют множество библиотек для любого языка. В этом руководстве мы будем использовать JavaScript с Node.JS, используя Express для HTTP и обработку маршрутов. Еще один популярный вариант с использованием C# — ASP.NET от Microsoft.

Если вы работаете на AWS, возможно, вам стоит изучить AWS API GateWay. Вместо того, чтобы запускать полноценный сервер API, API GateWay предоставляет дешевое управляемое решение, которое может выступать в качестве внешнего интерфейса для функций Lambda и RDS.

Настройка сервера API с помощью Express.JS

Express.JS — это фреймворк для веб-приложений, работающий на Node (серверный JavaScript). Он очень прост в использовании и хорошо сочетается с клиентскими приложениями JavaScript.

Создайте новую папку для сервера и запустите npm init , чтобы настроить файл package.json. Создайте App.js и вставьте следующее:

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => res.send('Message from Express route handler: Hello World!'))

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

Это базовый шаблон для простого сервера Express. Сам сервер создается с помощью express(). После этого регистрируются маршруты и связанные с ними функции-обработчики. В этом случае app.get(/, handler) регистрирует функцию-обработчик для запросов GET на маршруте /. Существуют и другие функции-обработчики для других глаголов HTTP, таких как POST и PUT.

В обработчике объект req представляет HTTP-запрос, а res — ответ. Затем res.send отправит базовые данные, например строку или объект JSON. Вы также можете использовать Express в качестве традиционного веб-сервера с res.sendFile, но мы рекомендуем использовать собственный сервер для повышения производительности со статическим объектом.

Для начала вы можете запустить node App.js, но лучше использовать nodemon, так как он будет отслеживать изменения в базовом файле и автоматически перезапускаться.

npm i -g nodemon

nodemon app.js

Если вы посетите localhost:3000 в своем браузере, вы должны увидеть экспресс-ответы на запросы.

В дополнение к нескольким функциям обработчика вы также можете сопоставлять множество различных маршрутов. Явная маршрутизация проста: app.get(/users) обработает запросы, отправленные /users. Вы также можете сопоставлять маршруты, используя подстановочные знаки и регулярные выражения. Вы даже можете вкладывать обработчики маршрутизатора; например, создание нового обработчика специально для подкаталога, такого как /users, который отделен от основного приложения и обычно хранится и экспортируется из собственного файла.

Однако все это по-прежнему обслуживается через HTTP, поэтому первым обновлением будет настройка HTTPS. С этим легко справиться; все, что вам нужно, это ваш закрытый ключ SSL и сертификат. Если вы просто тестируете, вы можете сгенерировать самоподписанный сертификат, используя openssl:

openssl req -nodes -new -x509 -keyout server.key -out server.cert

Вам придется вручную доверять этому сертификату, когда Chrome выйдет из строя, но он будет работать. Вместо того, чтобы вызывать listen для app, мы настроим HTTPS-сервер, передадим ему приложение, а затем прослушаем его.

const express = require('express')
var https = require('https')
var fs = require('fs')

const app = express()
const port = 3000

app.get('/', (req, res) => res.send('Message from Express route handler: Hello World!'))

https.createServer({
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.cert')
  }, app)
  .listen(port, () => console.log(`Example app listening on port ${port}!`))

Подключение базы данных

Этот шаг зависит от вашей конкретной базы данных, но на самом деле в этом нет ничего особенного. Все, что вам нужно сделать, это установить драйвер Node.JS для вашей базы данных, предоставить сведения о подключении к Express и подключиться к нему, как если бы вы использовали обычный JavaScript (или любой другой язык, который вы используете для создания своего сервера API).

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

docker run -d -p 27017-27019:27017-27019 --name mongodb mongo:4.0.4

Вы можете использовать MongoDB Compass для подключения к нему и выполнения административных задач.

Что касается Express, вам необходимо установить пакет MongoDB NPM для подключения к нему.

npm install mongodb

Поскольку мы не хотим, чтобы Express запускался до тех пор, пока база данных не будет подключена, мы переместим app.listen() внутри MongoClient.connect().

const express = require('express')
var https = require('https')
var fs = require('fs')
const MongoClient = require('mongodb').MongoClient

const app = express()
const port = 3000

app.get('/', (req, res) => res.send('Message from Express route handler: Hello World!'))

var db;
MongoClient.connect('mongodb://localhost:27017/', (err, client) => {
  if (err) return console.log(err)
    db = client.db('test') // whatever your database name is

  https.createServer({
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.cert')
  }, app)
  .listen(port, () => console.log(`Example app listening on port ${port}!`))
})

Теперь вы можете подключиться к Mongo, используя переменную db и любые стандартные методы. Вы должны убедиться, что используете async/await , иначе вы будете возвращать необработанные промисы.

app.get('/', async (req, res) => {
  const response = await db.collection('test').find().toArray();
  res.send(response)
})

Он подключается к базе данных, возвращает содержимое коллекции test и выдает его в виде массива JSON.

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

Кэширование запросов API для повышения производительности

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

Следует отметить, что вы никогда не должны кэшировать что-либо, требующее аутентификации для просмотра, например личную информацию пользователя. Общее правило заключается в том, что если страница одинакова для всех, вы можете кэшировать ее для всех. Методы PUT, DELETE и POST никогда не следует кэшировать.

Вы можете использовать для этого хранилище в памяти, такое как Redis, но простой кеш памяти работает довольно хорошо. Установите memory-cache из npm:

npm i memory-cache

Затем в App.js создайте новое промежуточное ПО для кэширования перед вашими маршрутами:

const cache = require('memory-cache');

let memCache = new cache.Cache();
let cacheMiddleware = (duration) => {
  return (req, res, next) => {
    let key = '__express__' + req.originalUrl || req.url;
    let cacheContent = memCache.get(key);
    if(cacheContent){
      res.send( cacheContent );
      return;
    } else {
      res.sendResponse = res.send;
      res.send = (body) => {
        memCache.put(key,body,duration*1000);
        res.sendResponse(body);
      }
      next()
    }
  }
}

Затем на маршрутах, которые вы можете кэшировать, вы можете использовать это промежуточное ПО перед основным обработчиком, чтобы кэшировать результаты на X секунд:

app.get('/products', cacheMiddleware(30), function(req, res){
  ...
});