Создание VueJS компонента

Введение

Мне очень нравится идея маленьких переиспользуемых компонент. Если передо мной встаёт задача добавить какой-нибудь функционал, я прежде всего трачу некоторое время на поиск уже существующего решения. Так и в этот раз. Немногие знают, что r2cloud - это полноценный REST сервер. А значит им можно управлять программно. Сейчас существует только один клиент для него - r2cloud-ui. Это приложение VueJS, которое предоставляет UI для управления. Однако, вся мощь REST сервисов заключается в том, что с ними можно взаимодействовать программно с помощью различных языков программирования. Это позволяет построить достаточно интересные интеграции и более сложные системы. Чтобы рассказать всему миру о том, как можно управлять r2cloud, я решил создать API документацию.

Самый простой создания документации - это записать все REST методы в html файл и добавить на сайт. Однако, за последние десятки лет, инженерная мысль шагнула дальше. Если описать REST API с помощью специальной схемы OpenAPI, то на её основе можно:

  1. Сгенерировать документацию
  2. Сгенерировать клиентскую библиотеку под различные языки программирования
  3. Сгенерировать заглушку для серверного кода

Второй и третий пункт у меня уже есть, а вот первый пункт мне как раз и нужен. Таким образом передо мной встала задача отрисовать спецификацию OpenAPI в VueJS.

{
	"/health": {
		"get": {
			"tags": [
				"System"
			],
			"summary": "Check if r2cloud is up",
			"responses": {
				"200": {
					"description": "If r2cloud is up"
				}
			}
		}
	}
}

Покопавшись немного в интернете я нашёл следующие наиболее близкие решения:

  • swagger-ui. Стандартная библиотека, позволяющая отрисовать спецификацию OpenAPI с помощью собственных стилей и Javascript.
  • vue-openapi. Позволяет отрисовать спецификацию OpenAPI с помощью библиотеки стилей vue-material.

В обоих случаях используются собственные стили компонентов. Эти стили не сочетаются с bootstrap, поэтому я решил написать небольшой компонент - vue-openapi-bootstrap. Он позволяет:

  • отрисовывать спецификацию OpenAPI 3.x
  • UI максимально близко повторяет стандартный swagger-ui
  • использует нативные компоненты из bootstrap 4.x и динамические компоненты из bootstrap-vue
  • отображает запросы и ответы API в формате json
  • улучшенное отображение доменных моделей

Создание компонента

Создание однофайлового компонента очень хорошо описано в официальной документации. В этой статье предлагается делать сборку компонента с помощью rollup. Насколько я понял, это ещё один способ сборки javascript кода, более легковесный, чем webpack. Из недостатков следует отметить отсутствие dev сервера и горячей перезагрузки модулей.

После того как написан весь boilerplate код и конфигурация сборки, написание компонента не представляет сложности. В случае моего компонента, мне удалось найти практически все стандартные компоненты bootstrap, которые позволили отобразить UI, похожий на swagger-ui.

<b-card-body>
  <p v-if="method.deprecated" class="text-muted">Warning: Deprecated</p>
  <p v-if="method.description">{{ method.description }}</p>
  <div v-if="method.parameters && method.parameters.length > 0">
    <h4>Parameters</h4>

Почему я выбрал UI совместимый со swagger-ui? Во-первых, у меня нет мнения о том, как должен выглядеть правильный UX для описания документации к API. А во-вторых, swagger-ui - это наиболее распространённый компонент для отображения OpenAPI документации.

Наибольшая сложность была с описанием того, что есть в стандарте OpenAPI 3.x. Дело в том, что стандарт позволяет достаточно гибко описывать различные REST API. А это значит, что он достаточно обширен и многословен. Чтобы всё это описать, я взял стандартный openapi.json из petstore и отрисовал всевозможные варианты конфигурации.

Финальный результат

Готовый компонент можно подключить следующим образом:

npm install vue-openapi-bootstrap

Использовать на странице:

<template>
  <vue-openapi-bootstrap :openapi="openapi"></vue-openapi-bootstrap>
</template>

<script>
import vueOpenapiBootstrap from 'vue-openapi-bootstrap/src/vue-openapi-bootstrap'
export default {
  components: {vueOpenapiBootstrap},
  data () {
    return {
      openapi: {}
    }
  }
}
</script>

В результате получаются такие страницы:

А вот так выглядит отображение документации в r2cloud-ui:

Сразу после публикации в npmjs.com в первые несколько дней, мой компонент был скачан 66 раз. Это лишний раз подтвердило мою мысль о том, что я на правильном пути и небольшой компонент востребован сообществом.

Выводы

  • VueJS продвигает создание небольших переиспользуемых компонент. Это очень мощная и правильная идея, которая позволяет собирать достаточно большие проекты из маленьких кусочков. Правильная реализация этой идеи делает создание компонентов действительно простым делом.
  • npmjs продвигает переиспользование кода. Как ещё объяснить те 66 скачиваний моего компонента, если я не давал рекламы и никому о нём не рассказывал?
  • Компонент есть куда улучшать: можно добавить поддержку отрисовки описаний с помощью markdown, задание доменной модели с помощью xml.