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

Введение в RAML – Язык моделирования RESTful API

Окончательное введение в RAML – язык моделирования RESTful API.

Автор оригинала: baeldung.

1. Обзор

В этой статье мы представляем Язык моделирования API RESTful (UML) , нейтральный к поставщикам язык с открытой спецификацией , построенный на YAML 1.2 и JSON для описания API RESTful.

Мы рассмотрим базовый синтаксис RAML 1.0 и структуру файлов, продемонстрировав, как определить простой API на основе JSON. Мы также покажем, как упростить обслуживание файлов RAML с помощью includes . И если у вас есть устаревшие API, которые используют схему JSON, мы покажем, как включить схемы в UML.

Затем мы представим несколько инструментов, которые могут улучшить ваше путешествие в RAML, включая инструменты разработки, генераторы документации и другие.

Наконец, мы завершим, описав текущее состояние спецификации RAML.

Дальнейшее чтение:

Двоичные форматы данных в API Spring REST

Руководство по спокойному отдыху

Создание микросервисов REST с помощью Javalin

2. Определение Вашего API (создание файла .raml)

API , который мы определим, довольно прост: учитывая типы сущностей Foo , определите основные операции CRUD и пару операций запроса. Вот ресурсы, которые мы определим для нашего API:

  • GET/api/v1/foos
  • POST/api/v1/foos
  • GET/api/v1/foos/{id}
  • PUT/api/v1/foos/{id}
  • УДАЛИТЬ/api/v1/foos/{id}
  • GET/api/v1/foos/name/{имя}
  • GET/api/v1/foos?name={name}&OwnerName={OwnerName}

И давайте определим наш API как апатридный, использующий базовую аутентификацию HTTP и доставляемый в зашифрованном виде по протоколу HTTPS. Наконец, давайте выберем JSON для нашего формата передачи данных (XML также поддерживается).

2.1. Настройки Корневого Уровня

Мы начнем с создания простого текстового файла с именем api.raml (рекомендуется префикс .raml ; имя произвольное) и добавим заголовок версии RAML в первую строку. На корневом уровне файла мы определяем параметры, которые применяются ко всему API:

#%RAML 1.0
title: Baeldung Foo REST Services API using Data Types
version: v1
protocols: [ HTTPS ] 
baseUri: http://myapi.mysite.com/api/{version}
mediaType: application/json

Обратите внимание в строке 3 на использование скобок { } вокруг слова ” версия “. Вот как мы сообщаем RAML, что ” версия” относится к свойству и должна быть расширена. Поэтому фактическим baseurl будет: http://myapi.mysite.com/v1

[Примечание: свойство version является необязательным и не обязательно должно быть частью baseUri .]

2.2. Безопасность

Безопасность также определяется на корневом уровне файла .raml . Итак, давайте добавим наше определение базовой схемы безопасности HTTP:

securitySchemes:
  basicAuth:
    description: Each request must contain the headers necessary for
                 basic authentication
    type: Basic Authentication
    describedBy:
      headers:
        Authorization:
          description: Used to send the Base64-encoded "username:password"
                       credentials
          type: string
      responses:
        401:
          description: |
            Unauthorized. Either the provided username and password
            combination is invalid, or the user is not allowed to access
            the content provided by the requested URL.

2.3. Типы данных

Далее мы определим типы данных, которые будет использовать наш API:

types:
  Foo:
    type: object
    properties:
      id:
        required: true
        type: integer
      name:
        required: true
        type: string
      ownerName:
        required: false
        type: string

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

types:
  Foo:
    properties:
      id: integer
      name: string
      ownerName?: string
  Error:
    properties:
      code: integer
      message: string

Символ”?”, следующий за именем свойства, объявляет, что это свойство не требуется.

2.4. Ресурсы

Теперь мы определим ресурс верхнего уровня (URI) нашего API:

/foos:

2.5. Параметры URI

Далее мы расширим список ресурсов, опираясь на наш ресурс верхнего уровня:

/foos:
  /{id}:
  /name/{name}:

Здесь фигурные скобки { } вокруг имен свойств определяют параметры URI. Они представляют заполнители в каждом URI и не ссылаются на свойства файла RAML корневого уровня, как мы видели выше в объявлении baseUri . Добавленные строки представляют ресурсы /foos/{id} и /foos/name/{name} .

2.6. Методы

Следующим шагом является определение методов HTTP, которые применяются к каждому ресурсу:

/foos:
  get:
  post:
  /{id}:
    get:
    put:
    delete:
  /name/{name}:
    get:

2.7. Параметры запроса

Теперь мы определим способ запроса коллекции foos с помощью параметров запроса. Обратите внимание, что параметры запроса определяются с использованием того же синтаксиса, который мы использовали выше для типов данных:

/foos:
  get:
    description: List all Foos matching query criteria, if provided;
                 otherwise list all Foos
    queryParameters:
      name?: string
      ownerName?: string

2.8. Ответы

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

Схема JSON может использоваться вместо типов данных для обратной совместимости с более ранней версией RAML. Мы представим схему JSON в разделе 3.

[Примечание: В приведенных ниже фрагментах кода строка, содержащая только три точки ( … ), указывает на то, что некоторые строки пропускаются для краткости.]

Давайте начнем с простой операции GET на /foos/{id}:

/foos:
  ...
  /{id}:
    get:
      description: Get a Foo by id
      responses:
        200:
          body:
            application/json:
              type: Foo
              example: { "id" : 1, "name" : "First Foo" }

Этот пример показывает , что, выполнив запрос GET на ресурсе /foos/{id} , мы должны вернуть соответствующий Foo в виде объекта JSON и кода состояния HTTP 200.

Вот как мы определили бы запрос GET для ресурса /food :

/foos:
  get:
    description: List all Foos matching query criteria, if provided;
                 otherwise list all Foos
    queryParameters:
      name?: string
      ownerName?: string
    responses:
      200:
        body:
          application/json:
            type: Foo[]
            example: |
              [
                { "id" : 1, "name" : "First Foo" },
                { "id" : 2, "name" : "Second Foo" }
              ]

Обратите внимание на использование квадратных скобок [], добавленных к типу Foo . Это демонстрирует, как мы определили бы тело ответа, содержащее массив объектов Foo , примером которого является массив объектов JSON.

2.9. Тело запроса

Затем мы определим тела запросов, соответствующие каждому запросу POST и PUT. Давайте начнем с создания нового объекта Foo :

/foos:
  ...
  post:
    description: Create a new Foo
    body:
      application/json:
        type: Foo
        example: { "id" : 5, "name" : "Another foo" }
    responses:
      201:
        body:
          application/json:
            type: Foo
            example: { "id" : 5, "name" : "Another foo" }

2.10. Коды состояния

Обратите внимание в приведенном выше примере, что при создании нового объекта мы возвращаем HTTP-статус 201. Операция PUT для обновления объекта вернет статус HTTP 200, используя те же органы запроса и ответа, что и операция POST.

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

Давайте посмотрим, как мы определим ожидаемый ответ на запрос GET на ресурсе /foos/{id} , когда ресурс с заданным идентификатором не найден:

        404:
          body:
            application/json:
              type: Error
              example: { "message" : "Not found", "code" : 1001 }

3. RAML Со Схемой JSON

До того, как типы данных были введены в RAML 1.0, объекты, тела запросов и тела ответов определялись с помощью схемы JSON.

Использование типов данных может быть очень мощным, но есть случаи, когда вы все еще хотите использовать схему JSON. В RAML 0.8 вы определили свои схемы, используя раздел корневого уровня схемы .

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

Вот как вы бы определили тип объекта Foo на корневом уровне файла .raml с помощью схемы JSON:

types:
  foo: |
    { "$schema": "http://json-schema.org/schema",
       "type": "object",
       "description": "Foo details",
       "properties": {
         "id": { "type": integer },
         "name": { "type": "string" },
         "ownerName": { "type": "string" }
       },
       "required": [ "id", "name" ]
    }

И вот как вы бы ссылались на схему в определении ресурса GET /foos/{id} :

/foos:
  ...
  /{id}:
    get:
      description: Get a Foo by its id
      responses:
        200:
          body:
            application/json:
              type: foo
              ...

4. Рефакторинг С Включением

Как мы видим из приведенных выше разделов, наш API становится довольно многословным и повторяющимся.

Спецификация RAML предоставляет механизм включения, который позволяет нам экстернализировать повторяющиеся и длинные разделы кода.

Мы можем реорганизовать наше определение API с помощью includes, сделав его более кратким и с меньшей вероятностью содержащим типы ошибок, которые возникают в результате методологии “копировать/вставлять/исправлять везде”.

Например, мы можем поместить тип данных для объекта Foo в файл types/Foot.ramp и тип для объекта Error в types/Error.raml . Тогда наш раздел типы будет выглядеть следующим образом:

types:
  Foo: !include types/Foo.raml
  Error: !include types/Error.raml

И если вместо этого мы используем схему JSON, наш раздел types может выглядеть следующим образом:

types:
  foo: !include schemas/foo.json
  error: !include schemas/error.json

5. Завершение API

После экстернализации всех типов данных и примеров в их файлы мы можем рефакторинговать наш API с помощью функции include:

#%RAML 1.0
title: Baeldung Foo REST Services API
version: v1
protocols: [ HTTPS ]
baseUri: http://rest-api.baeldung.com/api/{version}
mediaType: application/json
securedBy: basicAuth
securitySchemes:
  basicAuth:
    description: Each request must contain the headers necessary for
                 basic authentication
    type: Basic Authentication
    describedBy:
      headers:
        Authorization:
          description: Used to send the Base64 encoded "username:password"
                       credentials
          type: string
      responses:
        401:
          description: |
            Unauthorized. Either the provided username and password
            combination is invalid, or the user is not allowed to access
            the content provided by the requested URL.
types:
  Foo:   !include types/Foo.raml
  Error: !include types/Error.raml
/foos:
  get:
    description: List all Foos matching query criteria, if provided;
                 otherwise list all Foos
    queryParameters:
      name?: string
      ownerName?: string
    responses:
      200:
        body:
          application/json:
            type: Foo[]
            example: !include examples/Foos.json
  post:
    description: Create a new Foo
    body:
      application/json:
        type: Foo
        example: !include examples/Foo.json
    responses:
      201:
        body:
          application/json:
            type: Foo
            example: !include examples/Foo.json
  /{id}:
    get:
      description: Get a Foo by id
      responses:
        200:
          body:
            application/json:
              type: Foo
              example: !include examples/Foo.json
        404:
          body:
            application/json:
              type: Error
              example: !include examples/Error.json
    put:
      description: Update a Foo by id
      body:
        application/json:
          type: Foo
          example: !include examples/Foo.json
      responses:
        200:
          body:
            application/json:
              type: Foo
              example: !include examples/Foo.json
        404:
          body:
            application/json:
              type: Error
              example: !include examples/Error.json
    delete:
      description: Delete a Foo by id
      responses:
        204:
        404:
          body:
            application/json:
              type: Error
              example: !include examples/Error.json
  /name/{name}:
    get:
      description: List all Foos with a certain name
      responses:
        200:
          body:
            application/json:
              type: Foo[]
              example: !include examples/Foos.json

6. Инструменты RAML

Одна из замечательных вещей в RAML-это поддержка инструментов.

Существуют инструменты для анализа, проверки и создания API RAML; инструменты для генерации клиентского кода; инструменты для создания документации API в форматах HTML и PDF; а также инструменты, которые помогают нам тестировать спецификацию API RAML.

Существует даже инструмент, который преобразует API Swagger JSON в RAML.

Вот выборка доступных инструментов:

  • API Designer – веб-инструмент, ориентированный на быстрое и эффективное проектирование API
  • API Workbench – среда разработки, создания, тестирования и документирования RESTful API, поддерживающая как RAML 0.8, так и 1.0
  • RAML Cop – инструмент для проверки файлов RAML
  • RAML для JAX-RS – набор инструментов для создания скелета кода приложения Java + JAX-RS из спецификации RAML или для создания спецификации RAML из существующего приложения JAX-RS
  • RAML Sublime Plugin – плагин подсветки синтаксиса для текстового редактора Sublime
  • RAML to HTML – инструмент для создания HTML-документации из RAML
  • raml2pdf – инструмент для создания PDF-документации из RAML
  • RAML2Wiki – инструмент для создания вики-документации (с использованием разметки Confluence/JIRA)
  • Плагин SoapUI RAML – плагин RAML для популярного набора тестирования функциональных API SoapUI
  • Vigia – набор интеграционных тестов, способный генерировать тестовые случаи на основе определения RAML

Для получения полного списка инструментов RAML и связанных с ними проектов посетите страницу Проекты RAML .

7. Текущее состояние RAML

Спецификация RAML 1.0 (RC) получила статус кандидата на выпуск 3 ноября 2015 года, и на момент написания этой статьи ожидалось, что версия 1.0 будет завершена в течение месяца.

Его предшественник, RAML 0.8, был первоначально выпущен осенью 2014 года и до сих пор поддерживается множеством инструментов.

8. Дальнейшее Чтение

Вот некоторые ссылки, которые мы можем найти полезными в нашем путешествии с RAML.

9. Заключение

В этой статье представлен язык моделирования API RESTful (UML). Мы продемонстрировали некоторый базовый синтаксис для написания простой спецификации API с использованием спецификации RAML 1.0 (RC).

И мы увидели способы сделать наши определения более краткими, используя синтаксические ярлыки и экстернализируя примеры, типы данных и схемы в файлы “include”.

Затем мы представили набор мощных инструментов, которые работают со спецификацией RAML, чтобы помочь в повседневных задачах проектирования, разработки, тестирования и документирования API.

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