Как подменить ответ API без изменения бэкенда

Четыре способа отдать приложению свой JSON: Local Overrides в Chrome, MSW, перехватчик в клиенте и прокси. И когда какой.

Зачем это нужно

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

Chrome DevTools: Local Overrides

Самый быстрый способ для веба. Ставить ничего не надо.

  1. DevTools → Network → правый клик по запросу → Override content.
  2. Выберите папку на диске и дайте к ней доступ.
  3. Ответ откроется в редакторе. Правьте и сохраняйте через Ctrl/Cmd+S.
  4. Перезагрузите страницу. Теперь запрос отдаётся из вашего файла.

Ограничений два. Подменить можно тело и заголовки ответа, но не код статуса: 200 в 500 так не превратить. И работает это только в вашем браузере и только при открытых DevTools: закроете их, и вернётся настоящий ответ.

MSW: подмена в самом приложении

msw регистрирует на странице Service Worker. Приложение ходит в сеть как обычно, а отвечает ему ваш код.

Сначала положите файл воркера в публичную папку:

npx msw init ./public --save
// mocks/handlers.js
import { http, HttpResponse } from 'msw';

export const handlers = [
  http.get('/api/orders', () =>
    HttpResponse.json({ items: [] }),          // пустой список
  ),
  http.post('/api/orders', () =>
    new HttpResponse(null, { status: 500 }),   // ошибка сервера
  ),
];
// mocks/browser.js
import { setupWorker } from 'msw/browser';
import { handlers } from './handlers';

export const worker = setupWorker(...handlers);
// main.jsx — только в разработке
if (import.meta.env.DEV) {
  const { worker } = await import('./mocks/browser');
  await worker.start();
}
// приложение рендерим после этого

Дождитесь start() до рендера приложения. Запросы, ушедшие раньше, попадут на настоящий бэкенд.

Лучший вариант, когда подмена нужна повторяемо: это код, он лежит в репозитории, работает у всей команды, а в тестах те же обработчики подключаются через setupServer из msw/node. Минус в том, что способ ограничен своим веб-приложением: чужое не перехватите, трафик нативного клиента тоже.

Перехватчик в мобильном клиенте

Если исходники ваши, подменяйте там, где работает сеть.

// Android, OkHttp
val mockInterceptor = Interceptor { chain ->
    val request = chain.request()
    if (BuildConfig.DEBUG && request.url.encodedPath == "/api/orders") {
        Response.Builder()
            .request(request)
            .protocol(Protocol.HTTP_1_1)
            .code(500)
            .message("Mocked")
            .body("""{"error":"boom"}""".toResponseBody("application/json".toMediaType()))
            .build()
    } else {
        chain.proceed(request)
    }
}

val client = OkHttpClient.Builder()
    .addInterceptor(mockInterceptor)
    .build()

Проверку BuildConfig.DEBUG не убирайте. Без неё подмена уедет в релиз, к пользователям.

Цена способа: нужны исходники, и каждая правка требует пересборки.

Прокси: подмена снаружи приложения

Отладочный прокси подменяет ответ в сети, а не внутри приложения. Поэтому ему всё равно, чьё это приложение и на чём написано: веб-страница, нативный клиент на телефоне, CLI-утилита, чужая программа без исходников. Правило простое: на такой-то адрес отдать такой-то ответ, то есть статус, заголовки и тело, при желании с задержкой. Запрос, который попал под правило, в сеть вообще не уходит.

Это единственный из четырёх способов, который работает, когда:

  • приложение не ваше и пересобрать его нельзя;
  • трафик идёт с телефона, а не из браузера;
  • надо показать коллеге или тестировщику, не заставляя его разворачивать окружение.

Ограничение одно, и важное. Приложение с пиннингом сертификата не примет сертификат прокси: соединение не установится, и в этом трафике вы ничего не увидите и ничего не подмените.

Что выбрать

Нужно Чем
Посмотреть один раз в своём браузере Local Overrides
Сценарий для всей команды и для тестов MSW
Подмена внутри своего мобильного клиента перехватчик в коде
Чужое приложение или телефон, без пересборки прокси

Как увидеть это у себя

В Solpuga правило Map Local хранит ответ целиком: статус, заголовки и тело. Запрос, на который оно ответило, помечен в списке меткой Rule, и сразу видно, что правило сработало. Чаще всего при подмене правило просто не совпадает: не тот путь, в шаблоне остался параметр адреса, или приложение показывает данные из кэша. Полный справочник: Локальная подмена.

Посмотреть в Solpuga

Рядом