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.
- RAML.org – официальный сайт спецификации RAML
- json-schema.org – главная страница схемы JSON
- Понимание схемы JSON
- Генератор схем JSON
- Страница RAML в Википедии
9. Заключение
В этой статье представлен язык моделирования API RESTful (UML). Мы продемонстрировали некоторый базовый синтаксис для написания простой спецификации API с использованием спецификации RAML 1.0 (RC).
И мы увидели способы сделать наши определения более краткими, используя синтаксические ярлыки и экстернализируя примеры, типы данных и схемы в файлы “include”.
Затем мы представили набор мощных инструментов, которые работают со спецификацией RAML, чтобы помочь в повседневных задачах проектирования, разработки, тестирования и документирования API.
С предстоящим официальным выпуском версии 1.0 спецификации, в сочетании с подавляющей поддержкой разработчиков инструментов, похоже, что RAML здесь надолго.