ApiBlaze – это инструмент для изучения спецификаций API: поиск по ключевому слову, фильтрация объектов, свойств или конечных точек, а также просмотр описаний и примеров кода. ApiBlaze поможет вам молниеносно ответить на конкретный вопрос об API. Вы можете попробовать это здесь: apiblaze.admantium.com.

При поиске элементов API вы найдете объекты, свойства и конечные точки. При их выборе они будут отображаться по-разному: объекты показывают свою модель данных, свойства — список ранжированных объектов, в которых они появляются, а конечные точки — параметры запроса, а также сложные объекты ответа.

В этой статье мы рассмотрим изменения, необходимые для отображения свойств и конечных точек, и завершим процесс разработки ApiBlaze.

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

Обработка запросов на загрузку сведений

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

function apiElementsDetailsSearchAction (object) {
  switch (object.type) {
    case 'object':
      return loadObject(object)
    case 'property': 
      return loadProperty(object)
    case 'endpoint':
      return loadEndpoint(object)
}

Давайте продолжим смотреть, как загружаются свойства.

Поиск и визуализация свойств

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

  • Загрузите содержащий объект свойства
  • Загрузите определение свойства внутри содержащего объекта
  • Поиск во всех объектах, если они содержат это свойство, и сохранение всех имен этих объектов.

В результате получается следующая структура данных:

{
  "name": "imagePullSecrets",
  "containingObject": "io.k8s.api.core.v1.ServiceAccount",
  "type": "Property",
  "attrType": "array",
  "description": "ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod",
  "containingObjectList": [
    "io.k8s.api.core.v1.ServiceAccount",
    "io.k8s.api.core.v1.PodSpec"
  ]
}

Внешний интерфейс использует эту структуру и создает следующее представление:

Поиск и рендеринг конечных точек

Конечные точки — это уникальный объект, который требует особого отношения. Когда спецификация API загружена, конечные точки будут проиндексированы и разделены по их HTTP-методам. Например, когда принимаются оба метода GET и POST, будут созданы две записи. Вот пример:

{
  name: "POST /api/v1/namespaces/{namespace}/pods",
  containingObject: "/api/v1/namespaces/{namespace}/pods",
  type: "Endpoint",
  description: "create a Pod",
  score: 3
},
{
  name: "GET /api/v1/namespaces/{namespace}/pods",
  containingObject: "/api/v1/namespaces/{namespace}/pods",
  type: "Endpoint",
  description: "list or watch objects of kind Pod",
  score: 3
}

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

Шаги довольно сложные, поэтому давайте начнем с самого начала: исходная спецификация OpenAPI. Конечная точка post выглядит так:

"/api/v1/namespaces/{namespace}/pods": {
  "post": {
    "consumes": [
      "*/*"
    ],
    "description": "create a Pod",
    "operationId": "createCoreV1NamespacedPod",
    "parameters": [
      {
        "in": "body",
        "name": "body",
        "required": true,
        "schema": { 
          // ... 
        }
      },
      {
        "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
        "in": "query",
        "name": "dryRun",
        "type": "string",
        "uniqueItems": true
      },
      // ....
    ],
    "responses": {
      "200": {
        "description": "OK",
        "schema": {
          "$ref": "#/definitions/io.k8s.api.core.v1.Pod"
        }
      },
      // ...
    },
  }
}

Конечные точки имеют две интересные части информации: parameters и responses.

Обработка параметров конечной точки

Параметры могут быть переданы как параметры запроса, добавленные к URL-адресам. Или их можно передать внутри тела запроса в качестве полезной нагрузки JSON. В то время как параметры запроса представляют собой простые пары «ключ-значение», параметры тела представляют собой вложенные сложные объекты, рассмотренные в предыдущей статье.

Параметры обрабатываются с помощью следующих шагов:

  1. Отфильтровать все параметры со свойством in === 'query'
  • Для этих элементов сохраняйте только атрибуты description и type.

2. Отфильтровать все параметры, если есть один элемент со свойством in === 'body'

  • Для этого элемента обработайте его вложенный атрибут schema

Применение этих преобразований к вышеупомянутой конечной точке post приводит к следующей структуре данных:

"queryParameters": [
  "dryRun": {
    "_description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
    "_type": "string",
  },
  "fieldManager": {
    "_description": "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.",
    "_type": "string",
  }
  ]
},
"bodyParameters": {
  "apiVersion": {
    "_type": "string",
    "_description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources"
  },
  "kind": {
    "_type": "string",
    "_description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds"
  },
}

Параметры тела и параметры запроса будут отображаться в своих собственных кодовых полях. Как и прежде, структура JSON будет преобразована в строку, и будет применено несколько преобразований HTML.

renderEndpoint() {
  const { bodyParameters, queryParameters } = this.getState().searchApiElementDetails
  document.querySelector(this.querySelector).innerHTML = 
    this.style(this.format(bodyParameters), "Body Parameters") +
    this.style(this.format(queryParameters), "Query Parameters") +
}

Вот пример:

Обработка ответов конечной точки

В исходной спецификации OpenAPI ответы представляют собой сопоставление кодов состояния HTTP с объектами с description и schema. Вот пример кода состояния 200.

"/api/v1/namespaces/{namespace}/pods": {
  "post": {
    // ...
    "responses": {
      "200": {
        "description": "OK",
        "schema": {
          "$ref": "#/definitions/io.k8s.api.core.v1.Pod"
        }
      },
      // ...
    },
  }
}

Необязательный элемент schema указывает на вложенный объект, который будет обрабатываться. В результате получается следующая структура данных:

"responses": {
  "200": {
    "_description": "OK",
    "properties": {
      "_type": "object",
      "_description": "Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts.",
      "apiVersion": {
        "_type": "string",
        "_description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources"
      },
      "kind": {
        "_type": "string",
        "_description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds"
      }
      //...
    }
  },
  "201": {
    "_description": "Created",
    "properties": {
      "_type": "object",
      "_description": "Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts."
    }
  },
  //...
}

При отображении каждый код состояния представляет собой отдельный раздел с вложенным объектом, отображаемым в поле кода.

Требования к проекту ApiBlaze выполнены

Выполнив эти изменения, мы выполнили все требования ApiBlaze:

Поиск APIS

  • ✅ SEA01 — Поиск API по ключевому слову
  • ✅ SEA02 — Показать результаты поиска во всплывающем окне
  • ✅ SEA03 — Выберите результаты поиска с помощью клавиш со стрелками, введите и щелкните мышью

Поиск элементов API

  • ✅ SEL01 — Различать объекты, свойства и конечные точки
  • ✅ SEL02 — Поиск элементов API по ключевым словам
  • ✅ SEL03 — Показать результаты поиска во всплывающем окне
  • ✅ SEL04 — Выберите результаты поиска с помощью клавиш со стрелками, введите и щелкните мышью

Показать элементы API

  • ✅ DIS01 — Показать описание объектов
  • ✅ DIS02 — При выборе объекта: показать всю его модель данных
  • ✅ DIS03 — При выборе свойства: Показать, в каких объектах оно используется
  • ✅ DIS04 — Когда выбрана конечная точка: показать ее объект запроса и ответа.

Рамки

  • ✅ FRAME01 — Контроллер и маршрутизация
  • ✅ FRAME02 — Страницы и компоненты с отслеживанием состояния
  • ✅ FRAME03 — Действия
  • ✅ FRAME04 — Оптимизированная комплектация

Технологии

  • ✅ TECH01 — Используйте PlainJS и пользовательский фреймворк
  • ✅ TECH02 — Используйте SAAS для CSS
  • ✅ TECH03 — Используйте веб-сокеты для подключения внешнего и внутреннего интерфейса

Вывод

Путь разработки ApiBlaze был долгим и требующим больших знаний. Первоначально прототипированный в середине 2020 года, я перезапустил проект после долгого перерыва. Требования менялись: в дополнение к основным функциям я также хотел использовать WebSockets и использовать собственную структуру для углубления своих знаний. Неудивительно, что разработка фреймворка стала самостоятельным путешествием, и очень полезным для углубления знаний JavaScript. Когда я читаю о других фреймворках JavaScript и вижу, как они работают, я лучше понимаю их функции и то, как они помогают разрабатывать приложения. Наконец, я рад, что завершил это путешествие, и надеюсь, что вы будете использовать ApiBlaze для быстрого поиска в спецификациях API.