«1. Обзор

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

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

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

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

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 } DELETE /api/v1/foos/{id} GET /api/v1/foos/name/{name} GET /api/v1/foos?name={name}\u0026ownerName={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, что «версия» относится к свойству и должна быть расширена. Следовательно, фактический baseUri будет следующим: http://myapi.mysite.com/v1

[Примечание: свойство версии является необязательным и не обязательно должно быть частью 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, включая параметры URI, методы 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.

/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" }
              ]

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

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

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

/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" }

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

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

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

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

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

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

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

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

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

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

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" ]
    }

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

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

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

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

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

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

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

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

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

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

А если вместо этого мы используем схему JSON, наш раздел типов может выглядеть так:

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

#%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

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

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

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

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

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

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

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

Полный список инструментов RAML и связанных с ними проекты, посетите RAML Projects pa гэ.

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

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

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

8. Дополнительная литература

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

RAML.org — официальный сайт спецификации RAML json-schema.org — дом схемы JSON Понимание схемы JSON Генератор схем JSON Страница Википедии RAML

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

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

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

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

Next »

Eliminate Redundancies in RAML with Resource Types and Traits