Дизайн API Rails
У меня есть сайт rails, который в основном основан на REST, и я хочу добавить поддержку JSON API.
Для чистой базы кода я должен добавить эту поддержку в существующие контроллеры или создать новые контроллеры, которые обрабатывают только эти методы API, а затем переместить весь общий код в модели/помощники?
Ответы
Ответ 1
Я использовал оба метода: написание логики API в тех же контроллерах и создание отдельных контроллеров для запроса API.
Если это только API, небольшое приложение, используемое только вами, переходите к стандартным отношениям модели контроллера, которые предлагает рельсы. Код будет довольно чистым. Файл маршрутов также будет чистым.
Если у вас есть веб-сайт, и вы хотите построить API, сделайте это отдельно. Я построил его вместе с существующими контроллерами, и код был слишком запутанным. Я несколько раз обновлял код, но мне все равно не понравилось (это тоже вопрос личного вкуса).
Другим решением является создание контроллеров с префиксом. Пример: ApiUsersController
. Это заставит ваш файл routes.rb
выглядеть уродливым, потому что вам нужно вручную указать маршрут в соответствии с соответствующим методом контроллера.
Рабочее решение для меня состояло в том, чтобы переместить всю логику API в отдельные контроллеры в пространстве имен API. Пространства имен также позволяют вам управлять версиями API. Так, например, ваши маршруты будут:
GET /api/v1/users.json
POST /api/v1/users.json
И тогда в будущем вы можете создать другую версию API, скажем v2
, не нарушая существующие приложения, которые используют более старую версию API.
Здесь вы можете найти больше о пространствах имен: http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing
Удивительный учебник по REST-full API с версиями: http://railscasts.com/episodes/350-rest-api-versioning?view=asciicast
Ответ 2
Генераторы контроллеров Rails по умолчанию выполняют JSON-ответы.
Например, если у вас есть этот метод:
class UsersController < ApplicationController
def index
@users = User.all
end
end
Вы можете добавить ответ JSON так:
class UsersController < Application Controller
def index
respond_to do |format|
format.html
format.js { render :json => @users }
end
end
end
Теперь у вас есть два ответа для /users
-
http://someapp.com/users
-
http://someapp.com/users.json
Вы можете добавить еще один очень легко; например.
format.xml { render :xml => @users }
Теперь ваше приложение ответит на http://someapp.com/users.xml
Настройка json
Скорее всего, вы не захотите выводить все поля таблицы в json. Для этого посмотрите rails/jbuilder
. Он позволяет создавать структуры JSON со встроенным DSL-модулем.
Пример из jbuilder README
Jbuilder.encode do |json|
json.content format_content(@message.content)
json.(@message, :created_at, :updated_at)
json.author do
json.name @message.creator.name.familiar
json.email_address @message.creator.email_address_with_name
json.url url_for(@message.creator, format: :json)
end
if current_user.admin?
json.visitors calculate_visitors(@message)
end
json.comments @message.comments, :content, :created_at
json.attachments @message.attachments do |attachment|
json.filename attachment.filename
json.url url_for(attachment)
end
end
Производит следующий вывод:
{
"content": "<p>This is <i>serious</i> monkey business",
"created_at": "2011-10-29T20:45:28-05:00",
"updated_at": "2011-10-29T20:45:28-05:00",
"author": {
"name": "David H.",
"email_address": "'David Heinemeier Hansson' <[email protected]>",
"url": "http://example.com/users/1-david.json"
},
"visitors": 15,
"comments": [
{ "content": "Hello everyone!", "created_at": "2011-10-29T20:45:28-05:00" },
{ "content": "To you my good sir!", "created_at": "2011-10-29T20:47:28-05:00" }
],
"attachments": [
{ "filename": "forecast.xls", "url": "http://example.com/downloads/forecast.xls" },
{ "filename": "presentation.pdf", "url": "http://example.com/downloads/presentation.pdf" }
]
}