@distributedlab/jac
TypeScript icon, indicating that this package has built-in type declarations

1.0.0-rc.16 • Public • Published

@distributedlab/jac

A library for constructing JSON-API compliant requests and responses.

version (scoped package) types tree-shaking checks

Example

Bearer token

interceptors.ts

import {
  Fetcher,
  FetcherErrorResponseInterceptor,
  FetcherRequest,
  FetcherRequestInterceptor,
  FetcherResponse,
  HTTP_METHODS,
  HTTP_STATUS_CODES,
} from '@distributedlab/fetcher'

import { DEFAULT_BUS_EVENTS } from '@/enums'
import { toolkitBus } from '@/globals'
import { i18n } from '@/localization'

export const bearerAttachInterceptor: FetcherRequestInterceptor = async (
  request: FetcherRequest,
) => {
  const accessToken = localStorage.getItem('accessToken')

  if (!accessToken) return request

  if (!request.headers) request.headers = {}

  // Attach bearer token to every request
  request.headers = {
    ...request.headers,
    Authorization: `Bearer ${accessToken}`,
  }

  return request
}

export const refreshTokenInterceptor: FetcherErrorResponseInterceptor = async (
  response: FetcherResponse<unknown>,
) => {
  const config = response?.request
  const isUnauthorized = response.status === HTTP_STATUS_CODES.UNAUTHORIZED

  // If error isn't unauthorized - return error
  if (
    !isUnauthorized
    // Add if you use a refresh token (as 'refresh_token_url' there should be refresh token endpoint)
    // && config.url !== 'refresh_token_url'
  )
    return response

  // Some authentication store in the client app
  const { t } = i18n.global

  try {
    const accessToken = localStorage.getItem('accessToken')

    // Executes some refresh token logic in the client app
    toolkitBus.emit(DEFAULT_BUS_EVENTS.refreshToken)

    const url = new URL(config.url)

    return new Fetcher({ baseUrl: url.origin }).request({
      endpoint: url.pathname,
      method: config.method as HTTP_METHODS,
      ...(config.body ? { body: config.body } : {}),
      headers: {
        ...config.headers,
        // Reset default authorization header with new token
        Authorization: `Bearer ${accessToken}`,
      },
    })
  } catch (error) {
    /** Example of handling refresh token error in the client app
     *
     * Implementation may differ from example
     *
     * We can logout user and redirect him to the login page and
     * emit bus error event to show user that session expired
     */

    toolkitBus.emit(DEFAULT_BUS_EVENTS.logout)
    toolkitBus.emit(DEFAULT_BUS_EVENTS.error, {
      title: t('api-errors.session-expired-title'),
      message: t('api-errors.session-expired-desc'),
    })
    return Promise.reject(error)
  }
}

api.ts

import { JsonApiClient } from '@distributedlab/jac';
import { bearerAttachInterceptor, refreshTokenInterceptor } from '@/interceptors';

export const api = new JsonApiClient(
  { baseUrl: 'https://api.example.com' },
  [{ request: bearerAttachInterceptor, error: refreshTokenInterceptor }],
)

Changelog

For the change log, see CHANGELOG.md.

Readme

Keywords

none

Package Sidebar

Install

npm i @distributedlab/jac

Weekly Downloads

607

Version

1.0.0-rc.16

License

MIT

Unpacked Size

319 kB

Total Files

80

Last publish

Collaborators

  • arvolear
  • artsuslov
  • napalmpapalam
  • volendi