Echolot
Моки

Маршруты на JavaScript

Ответы на запросы к моку на JavaScript до его остальных маршрутов и спецификации, с состоянием, которое хранится, пока мок работает.

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

Написание маршрутов

Откройте мок на странице «Моки» и прокрутите до карточки Маршруты на JavaScript. Напишите маршруты в редакторе и нажмите Сохранить маршруты. Вернуть возвращает то, что было сохранено.

Карточка «Маршруты на JavaScript» мока с кодом, который хранит заказы в списке, строка Running: POST /orders, GET /orders/:id под редактором и журнал, где у каждого запроса к заказам указан ответивший маршрут скрипта

В этом примере, для мока спецификации Alpenglow, хранятся заказы, которые делает клиент, и возвращаются по ID:

let orders = []

mock.post("/orders", (req, res) => {
  const order = { id: "ord_" + (orders.length + 1), status: "pending", ...req.json() }
  orders.push(order)
  res.status(201).header("Location", "/v1/orders/" + order.id).json(order)
})

mock.get("/orders/:id", (req, res) => {
  const order = orders.find(o => o.id === req.params.id)
  return order ?? res.status(404).json({ error: "no such order" })
})

После сохранения карточка перечисляет маршруты, которые зарегистрировал скрипт (Running: POST /orders, GET /orders/:id), или оранжевым — почему скрипт не загрузился. Маршруты хранятся в mocks/<name>.js рядом с настройками мока, так что вместе с рабочим пространством попадают в Git.

Когда выполняются маршруты

  • Маршруты на JavaScript отвечают первыми, до маршрутов, созданных вручную, и спецификации. Отвечает первый маршрут, у которого совпали метод и путь.
  • Пути отсчитываются от пути сервера спецификации, если мок обслуживает спецификацию: пишите /orders, а не /v1/orders.
  • Маршрут, который ничего не задаёт и ничего не возвращает, передаёт запрос дальше — маршрутам, созданным вручную, и спецификации, которые отвечают как обычно. Так можно обрабатывать лишь некоторые запросы, например с определённым параметром запроса.
  • Скрипт выполняется один раз, когда мок запускается. Его переменные верхнего уровня и объект state живут, пока мок не остановится.
  • Сохранение перезапускает маршруты с чистым состоянием. Изменения спецификации, маршрутов, созданных вручную, или настроек мока его сохраняют.
  • Запросы обрабатываются по одному, поэтому состояние остаётся согласованным.

Журнал мока помечает каждый запрос, обработанный маршрутом, именем маршрута: наведите на него указатель, чтобы увидеть Ответил этот маршрут или Передан дальше этим маршрутом (маршрутам, созданным вручную, или спецификации). То, что маршрут выводит через console.log, появляется в журнале под запросом.

API маршрутов

Маршруты регистрируются через mock и метод:

ФункцияСоответствует
mock.get(path, handler)GET
mock.post, mock.put, mock.patch, mock.delete, mock.head, mock.optionsЭтому методу
mock.any(path, handler)Любому методу

В пути :name соответствует одному сегменту и помещает его в req.params.name; * соответствует остатку пути.

Обработчик получает req и res:

reqЧто содержит
req.methodМетод, заглавными буквами.
req.pathПуть, отсчитываемый от пути сервера спецификации.
req.paramsСегменты пути :name.
req.queryПараметры запроса, для каждого имени — последнее значение.
req.headersЗаголовки, с именами в нижнем регистре.
req.bodyТело как текст.
req.json()Тело, разобранное как JSON, или null, если тела нет.
resЧто делает
res.status(code)Задаёт статус. По умолчанию 200.
res.header(name, value)Добавляет заголовок.
res.json(value)Отправляет значение как JSON с Content-Type: application/json, если вы не задали другой.
res.send(text)Отправляет текст с Content-Type: text/plain; charset=utf-8, если вы не задали другой.

Каждая функция res возвращает res, поэтому вызовы можно объединять в цепочку: res.status(201).json(order). Значение, которое возвращает обработчик, отправляется как JSON, так что return order — то же, что res.json(order). Обработчики могут быть async.

state (он же mock.state) — объект, который сохраняется между запросами, для того, что вам не хочется держать в собственной переменной:

mock.get("/me", (req, res) => {
  state.calls = (state.calls ?? 0) + 1
  if (state.calls % 3 === 0) return res.status(503).json({ error: "try again" })
  // Nothing set: the routes made by hand or the spec answer this request.
})

Ограничения

Маршруты выполняются в той же песочнице, что и скрипты запросов, а не в Node: без файловой системы и без сети. На каждый запрос JavaScript может работать 2 секунды, и ещё 2 секунды у скрипта есть на запуск. Обработчик, который выбрасывает исключение, отвечает 500 с текстом ошибки, она видна и в журнале.

Доверие к маршрутам

Маршруты — это код, который выполняется на вашем Mac, поэтому для них то же правило, что и для скриптов запросов. Маршруты, которые вы пишете и сохраняете в Echolot, выполняются. Маршруты, пришедшие извне — через Git, импорт или другое приложение, которое правит файл, — нет: карточка сообщает Эти скрипты пришли не из Echolot, и мок не запускается, пока вы не прочитаете их и не нажмёте Доверять скриптам. Если они снова изменятся вне Echolot, Echolot спросит ещё раз.

Агенты могут читать маршруты мока, но никогда не пишут их.

Из командной строки

echolot mock -w <workspace> <mock> запускает мок рабочего пространства со всеми его маршрутами; --routes <file> запускает маршруты на JavaScript из другого файла, в том числе вместе с файлом спецификации. См. echolot mock.

На этой странице