Рубрики
Без рубрики

Сделайте Fetch лучше, и ваши методы запроса API легче реализовать

В этом посте я поделюсь своей мыслью о том, как мне нравится структурировать методы, как получить данные из вашего … Tagged с WebDev, JavaScript, TypeScript, Node.

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

Этот метод также будет полезен в том, что когда -либо в рамках или платформе вы находитесь, как React, Angular, Vue или даже Nodejs (с несколькими многофилсами, например, Fetch …)!

Ох, и немного головы. Мы идем объектно-ориентированным программированием. Итак, базовое понимание классы JavaScript и Fetch API было бы хорошо, прежде чем вы продолжите.

Конечная игра

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

users = await backend.users.get()

Вместо чего -то подобного:

const res = await fetch('/users', {
  headers: {
    Authorization: '********',
    lang: 'en'
  }
})

if(!res.ok) throw new Error(res.statusText)

users = await res.json()

Мотивация

Так зачем проходить этот процесс? Ну, во -первых, это сделает ваш код легче читать Анкет Вы получите весь код от Fetch, скрытого за вызовами пояснительного метода. Как Backend.get.users () , это имеет смысл и короткий.

Конечно, вы можете извлечь логику в функцию с именем getUsers () и сделайте вызов туда. Но тогда вот следующее преимущество: Не повторяйте себя Анкет Без хорошей структуры для ваших запросов на бэк -конце вы будете Определенно Повторите себя. Установка авторизации и других заголовков в нескольких местах или просто для того, чтобы посмотреть, является ли вызов извлечения ОК везде…

Вы также можете перенести этот код в библиотеку для использования в ваших веб -приложениях и службах узлов без хлопот.

Давайте начнем

Код можно найти здесь Анкет

Таким образом, мы начнем с создания собственной «мини -мини -мини -версии» Axios (или вставьте имя HTTP -клиента здесь):

class HttpClient {
  constructor(options = {}) {
    this._baseURL = options.baseURL || "";
    this._headers = options.headers || {};
  }
}

Мы начинаем все с конструктора, мы примем два варианта, когда создам класс:

Базовый URL будет использоваться для построения URL. Позже мы будем использовать подобный метод получить get ('/users') И если мы определили baseurl с https://jsonplaceholder.typicode.com URL -адрес запроса будет https://jsonplaceholder.typicode.com/users

Заголовки будет набор заголовков по умолчанию, который будет отправлен с каждым запросом.

Если вы думаете: «Что с _ перед именами свойств? “Ну, я намерен быть этими свойствами, чтобы быть частным . Означало только использование внутри этих (или унаследованных) классов. Не из никого из того, что в реальном коде приложения. Вскоре для этого также будет синтаксис, который реализует поведение, Проверь это

Мы, вероятно, также должны добавить некоторый способ установить заголовки:

setHeader(key, value) {
    this._headers[key] = value;
    return this;
  }

В конце метода Setheader я добавил вернуть это Анкет Это добавлено, чтобы мы могли цепь метод вызовы. Например, при создании класса HTTPClient:

const httpClient = new HttpClient({baseURL: 'xxx'})
                     .setBasicAuth("user", "pass")
                     .setHeader("lang", "en")

Теперь в примере выше я использовал другой метод SetBasicauth . Я пропущу это сейчас, но в конце этого поста вы найдете некоторое вдохновение для большего количества свойств и вещей, которые вы можете добавить к клиенту.

Давайте сделаем запросы!

Это будет сделано через два шага. Прежде всего, мы определим нашу собственную функцию обертки для Fetch, а затем сделаем отдельные методы для получить/post/put/delete/patch :

async _fetchJSON(endpoint, options = {}) {
  const res = await fetch(this._baseURL + endpoint, {
    ...options,
    headers: this._headers
  });

  if (!res.ok) throw new Error(res.statusText);

  if (options.parseResponse !== false && res.status !== 204)
    return res.json();

  return undefined;
}

Таким образом, эта функция обертки просто заставляет Fetch вести себя немного больше, как я хочу, чтобы она это делала в этом конкретном случае использования. Как тот факт, что Fetch не бросает на плохие запросы.

Первый аргумент – это только конечная точка (строка), и если мы установим baseurl Вариант это будет относительно этого.

И аргумент параметров – это просто выборка Запрос Объект мы можем добавить дополнительные свойства. Это может быть пустым, но больше информации о доступной Свойства найдены здесь Анкет

Ой! Но я добавляю добавление СПАСПОЛНЕЧЕНИЕ Варианты на этот аргумент, чтобы сказать, следует ли реагировать на JSON или нет. Для большей части моих вариантов использования я хочу отказаться от анализа. Поэтому, если оставить пустым, диапазон выполняется, если не API явно утверждает Нет контента Анкет

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

Теперь давайте разместим некоторые способы выполнения запроса. Надеемся, что это должно быть прямо:

get(endpoint, options = {}) {
  return this._fetchJSON(
    endpoint, 
    { 
      ...options, 
      method: 'GET' 
    }
  )
}

post(endpoint, body, options = {}) {
  return this._fetchJSON(
    endpoint, 
    {
      ...options, 
      body: JSON.stringify(body), 
      method: 'POST' 
    }
  )
}

delete(endpoint, options = {}) {
  return this._fetchJSON(
    endpoint, 
    {
      parseResponse: false,
      ...options, 
      method: 'DELETE' 
    }
  )
}

/** AND SO ON */

Мы просто называем наш _fetchjson Метод и установите некоторые параметры, чтобы метод HTTP соответствовал названию нашего метода, и, возможно, установите правильное тело, чтобы о нем позаботились.

Теперь мы могли бы просто сделать некоторые звонки API:

const httpClient = new HttpClient({baseURL: 'https://example.com'})
                     .setHeader('lang', 'sv')

const users = await httpClient.get('/users')

На шаг впереди: Клиент API

Мы много сделали! Этот клиент является нашим собственным «мини-мини-мини-мини-версией» Axios. Что мы легко можем расширить любые параметры, параметры или функции, которые нам понадобятся.

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

Но , этот класс сейчас служит своей цели, верно? Это может работать самостоятельно и быть полезным таким образом. Так что, если мы позволим классу httpclient быть нашим базовым классом, и мы сможем унаследовать этот, чтобы создать наш класс Apiclient.

Таким образом, мы можем сделать другие httpclients для беседы с другими службами, используя класс httpclient напрямую. И общение с нашим бэкэнд с классом Apiclient, что просто добавляет к существующей функциональности.

Унаследование класса HTTPClient будет выглядеть так:

import HttpClient from "./http-client"

class ApiClient extends HttpClient { 
  constructor(baseURL, langCode) {
    super({
      baseURL,
      headers: {
        lang: langCode
      }
    });
  }

  get users() {
    return {
      get: () => this.get("/users"),
      delete: (id) => this.delete(`/users/${id}`),
      create: (user) => this.post("/users", user),
      update: (user) => this.put(`/users/${user.id}`, user)
    };
  }
}

export default ApiClient

Ну, это было довольно быстро. Мы только что добавили наш маленький аромат в конструктор, и мы могли бы просты и быстро определить наши конечные точки.

И добавление дополнительных конечных точек теперь очень просты и надежно.

Возьмите это дальше

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

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

Некоторые вещи, которые вы могли бы сделать дальше, если это применимо к вашим потребностям:

Добавьте помощников к аутентификации, если вы не полагаетесь на файлы cookie

Например, если вам нужна базовая аутентификация:

setBasicAuth(username, password) {
  this._headers.Authorization = `Basic ${btoa(`${username}:${password}`)}`
  return this
}

Просто помните, что BTOA не доступен во всем мире в Nodejs. Но просто многофилью, и все будет хорошо.

И для авторитета:

setBearerAuth(token) {
  this._headers.Authorization = `Bearer ${token}`
  return this
}

Сделайте функции общими, если вы находитесь в TypeScript

Мне нравится TypeScript, 90% всего моего кода находится в TypeScript. При создании этого для TypeScript Добавьте общий тип возврата к функциям, и для ваших методов публикации вы должны ввести ожидаемое тело:

_fetchJSON(endpoint: string, options: RequestInit = {}):Promise{ /**/ }

Я обычно делаю немного взлома, когда тело не проанализировано, и скажу вернуть неопределенные, как любой Чтобы просто получить TypeScript, чтобы не жаловаться. Если вы ожидаете неопределенного T должен быть неопределенное И тебе приятно идти.

И в вашем клиенте API для такого запроса на сообщение:

users = {
  post: (user:IUser) => this.post('/users', user)
}

Добавьте методы в любой применимый заголовок, который ожидает ваш API/можешь использовать

Например, на работе у нас есть заголовок, чтобы включить или исключать пустые значения в ответ (чтобы сэкономить некоторое время, передавая большие коллекции)

includeEmptyAndDefault(shouldInclude) {
  if(shouldInclude) {
   this._headers.IncludeEmptyAndDefault = 1
  } else {
   this._headers.IncludeEmptyAndDefault = 0
  }
  return this
}

Создайте пакет

Используйте RULLUP или же TSDX, если у вас есть TypeScript, Если вы хотите сделать отдельный пакет. Таким образом, клиент API может быть использован в качестве модуля и в других проектах. Это может быть здорово для вас и ваших клиентов, чтобы все происходило быстро.

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

Фотография обложки Флориана Крамма на Неспособный

Оригинал: “https://dev.to/stroemdev/make-fetch-better-and-your-api-request-methods-easier-to-implement-e9i”