npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pushwoosh/http-client

v2.10.1

Published

Этот пакет является частью микрофронтендовой архитектуры <br/> Предназначен для выполнения запросов к API с использованием OAuth2 протокола

Readme

Pushwoosh / Micro Frontends / Http Client

Этот пакет является частью микрофронтендовой архитектуры Предназначен для выполнения запросов к API с использованием OAuth2 протокола

Установка

  1. Сгенерировать ключи для запуска сервера в режиме HTTPS (Confluence)
  2. Выполнить npm ci

Запуск разработки

  1. Скопировать файл .env.example в .env
  2. Выполнить npm start

Использование

Работу с Http Client можно разделить на несколько условных частей:

  1. Создание экземпляра
  2. Авторизация (этот шаг может быть пропущен)
  3. Выполнение запросов
  4. Обработка ответов
  5. Обработка ошибок

Создание экземпляра

Первым делом нужно создать экземпляр HttpClient

const httpClient = new HttpClient(history, config);

Где: history - API для работы с навигацией config - конфигурация Http Client config.defaultResponseMiddleware - обработчик ответа от сервера по умолчанию (см. раздел обработка ответов от сервера) config.defaultErrorMiddleware - обработчик ошибок по умолчанию (см. раздел обработка ошибок)

import { createBrowserHistory } from 'history';
import { defaultErrorMiddleware, defaultResponseMiddleware, HttpClient } from '@pushwoosh/http-client';

// создаем API для работы с навигацией
const history = createBrowserHistory();

// формируем конфигурацию Http Client
const config = {
  // обязательное поле: описывает адреса для выполнения внутренних запросов HttpClient к серверу авторизации
  // для более подробной инфорации смотри https://www.rfc-editor.org/rfc/rfc6749.html#section-1.1 - authorization server
  urls: {
    // обязательное поле: адрес для получения authorization code и authorization state
    // для более подробноей информации смотри https://www.rfc-editor.org/rfc/rfc6749.html#section-4.1.1 
    authorize: 'https://sso.pushwoosh.com/authorize',
    // обязательное поле: адрес для получения access token и refresh token
    token: 'https://sso.pushwoosh.com/token',
    // обязательное поле: адрес для завершения сессии
    logout: 'https://sso.pushwoosh.com/logout',
  },
  // обязательное поле: идентификатор клиента, свзязан с сервером SSO, зависит от домена на котором работает HttpClient
  // для более подробной инфорации смотри https://www.rfc-editor.org/rfc/rfc6749.html#section-1.1 - client
  clientId: 'APP_FRONT',
  // обязательное поле: область ограничений на работу с защищенными ресурсами
  // для более подробной инфорации смотри https://www.rfc-editor.org/rfc/rfc6749.html#section-1.1 - resource server
  scope: 'cp-pushwoosh customer-journey',
  // обязательное поле: параметры куки для сохранения authorization state и url before authorize
  cookie: {
    // обязательное поле: определяет домен на котором будут доступны куки
    domain: '.pushwoosh.com',
    // определяет время жизни кук
    expires: 300,
    // определяет путь, где будут доступны куки
    path: '/',
    // определяет будут ли передаваться куки только по https протоколу
    secure: true,
    // определяет при каких условиях куки будут отправлятся на сервер при выполнении кроссдоменных запросов 
    sameSite: 'none',
  },
  // обязательное поле: бызовый обработчик ответов от сервера
  basicResponseMiddleware: defaultResponseMiddleware,
  // обязательное поле: базовый обработчик ошибкок при выполнении запросов
  basicErrorMiddleware: defaultErrorMiddleware,
};

Авторизация

Этот шаг может быть пропущен, если access token получается другим способом. Если требуется произвести авторизацию клиента с помощью SSO, то нам нужно выполнить 2 действия:

  1. Получить Basic Authorization путем перехода на сервер авторизации и возвращения обратно с authorization code и authorization state
    await httpClient.login();
  2. Получить Bearer Authorization путем выполнения запроса к серверу авторизации и получения access token и refresh token с помощью authorization code
    const introspect = await httpClient.authorize(authorization);

Полный пример выполнения авторизации клиента:

// получаем authorization code и authorization state из строки браузера
const query = parse(window.location.search.slice(1));
const authorizationCode = typeof query.code === 'string' ? query.code : null;
const authorizationState = typeof query.state === 'string' ? query.state : null;
const authorization = authorizationCode && authorizationState
  ? { code: authorizationCode, state: authorizationState }
  : null;

// выполняем авторизацию
if (authorization) {
  const introspect = await httpClient.authorize(authorization);
  if (!introspect) {
    await httpClient.login();
    return;
  }
}

Выполнение запросов:

Для выполнения запросов можно использовать следующий метод:

import { defaultErrorMiddleware } from './http-client.utilities';

type Result = {
  readonly data1: string;
  readonly data2: number;
};

type Params = {
  readonly param1: string;
  readonly param2: number;
}

type Query = {
  readonly query1: string;
  readonly query2: number;
}

type Body = {
  readonly body1: string;
  readonly body2: number;
}

const url = '/entrypoint/:param1/:param2';
const method = Method.POST;
const options = {
  // определяет заголовки, которые будут отправлены вместе с запросом
  headers: {
    'Some-Header': 'Some-Value',
  },
  // параметры для заполнения адреса запроса
  params: {
    param1: 'value-param',
    param2: 1,
  },
  // параметры запроса
  query: {
    query1: 'value-query',
    query2: 2,
  },
  // тело запроса
  body: {
    body1: 'value-body',
    body2: 3,
  },
  // обязательное поле: определяет требуется ли передавать данные об авторизации
  withAuthorization: true,
  // определяет требуется ли отправлять заголовки в кроссдоменных запросах
  withCredentials: false,
  // определяет какой обработчик ответа будет использован (см. разедл обработка ответа от сервера)
  responseMiddleware: defaultResponseMiddleware,
  // определяет какой обработчик ошибок будет использован (см. разедл обработка ошибок)
  errorMiddleware: defaultErrorMiddleware,
};

const { data1, data2 } = await httpClient.request<Method.POST, Result, Params, Query, Body>(url, method, options);

Он эквивалентен следующему запросу:

curl -XPOST 'https://pushwoosh.com/entrypoint/value-param/1?query1=value-query&query2=2' -H "Some-Header: Some-Value" -H "Authorization: Bearer ..." -d '{
  "body1": "value-body",
  "body2": 3
}'

Также существуют упрощенные варианты запросов:

GET
const result = httpClient.get<Result, Params, Query>(url, options);
POST
const result = httpClient.post<Result, Params, Query, Body>(url, options);
PUT
const result = httpClient.put<Result, Params, Query, Body>(url, options);
PATCH
const result = httpClient.patch<Result, Params, Query, Body>(url, options);
DELETE
const result = httpClient.delete<Result, Params, Query, Body>(url, options);

Обработка ответов от сервера

Так как ответ от сервера не стандартизирован, то при обращении к разным эндпоинтам может потребоваться своя валидация и парсинг. Для этого в каждом запросе можно указать свой обработчик запроса. Например, если ответ от сервера всегда 200, а внутри него лежит JSON с данными, то можно поступить следующим образом:

type Result = {
  readonly data1: string;
  readonly data2: number;
};

type JSONResponse = {
  readonly result: Result;
  readonly code: number;
  readonly message: string;
};

const { data1, data2 } = await httpClient.post<Result, never, never, never>('/entrypoint', {
  withAuthorization: true,
  responseMiddleware: (response) => {
    const jsonResponse = defaultResponseMiddleware<JSONResponse>(response);
    if (jsonResponse.code !== 200) {
      switch (jsonResponse.code) {
        case 210:
        case 401:
          throw new UnauthorizedError(jsonResponse.message, response.details);
        default:
          throw new UntiledError(jsonResponse.message, jsonResponse.code, response.details);
      }
    }

    return jsonResponse.result;
  },
});

При обработке ответа от сервера очень важно корректно указывать ошибки, так как:

  1. Если при обработке ответа от сервера будет кинуто исключение UnauthorizedError, то HttpClient попробует обновить access token м выполнить запрос повторно
  2. Настраивается глобальный обработчик ошибок, который при возникновении тех или иных ситуаций их обрабатывает

Обработка ошибок

Если в момент выполнения запроса происходит ошибка, то в первую очередь ее пробует обработать basicErrorMiddleware (если для конкретного запроса он не заменен на свой обработчик ошибок)

import { ForbiddenError, HttpClientError, UnauthorizedError } from './http-client.errors';

const httpClient = new HttpClient(history, {
  basicErrorMiddleware: async (error: unknown): Promise<never> => {
    // если клиент не авторизован и пытается выполнить запрос к приватным данным, то пробуем его авторизовать
    if (error instanceof UnauthorizedError) {
      await httpClient.logout();
      await httpClient.login();
    }
    
    throw error;
  },
});

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

Ошибки:

Все ошибки наследуются от родительского класса HttpClientError. Существуют следующие ошибки:

  1. HttpClientError:
    1. LogicError - ошибка в логике самого Http Client
    2. ClassifiedError - категоризированная ошибка, никогда не используется как отдельный экземпляр, от нее наследуются все остальные ошибки.
      1. UntiledError - ошибка не попавшая ни под одну из категорий ниже
      2. BadRequestError - некорректный запрос (сервер не может обработать запрос из-за некорректного синтаксиса)
      3. UnauthorizedError - не авторизован / некорректная авторизация
      4. ForbiddenError - запрещено для выполнения (permissions)
      5. NotFoundError - не найдено
      6. MethodNotAllowedError - не доступно для выполнения (restrictions)
      7. PayloadTooLargeError - слишком большой запрос
      8. UnsupportedMediaTypeError - неподдерживаемое тип медиа
      9. UnprocessableEntityError - сервер понял запрос, но не смог его обработать из-за логических ошибок
      10. TooManyRequestsError - слишком много запросов
      11. InternalServerError
      12. NotImplementedError
      13. BadGatewayError
      14. ServiceUnavailableError
      15. GatewayTimeoutError

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