Итак, немного фона. Я создаю сайт с довольно полным api. Api должен иметь возможность обрабатывать изменения, поэтому я выполнил версию api с api url эквивалентом чего-то вроде /api/0.2/$apiKey/$controller/$action/$id
.
Я хочу, чтобы иметь возможность повторно использовать мои контроллеры для api, а также стандартное представление html. Сначала решение было использовано с блокомFormat во всех моих действиях (через частную функцию, совместно используемую в моих блоках действий).
Мне не нравится дубликат кода, и поэтому я хочу централизовать функционалFormat. поэтому вместо того, чтобы иметь кучу контроллеров и действий, имеющих свой собственный блокFormat, я бы хотел, чтобы это была либо услуга (однако у нас нет доступа к render()
на сервисах, не так ли?) или у вас есть фильтр, который может отображать выходные данные в соответствии с согласованием содержимого графиков.
В моем текущем решении указан этот фильтр:
after = { model ->
def controller = grailsApplication.controllerClasses.find { controller ->
controller.logicalPropertyName == controllerName
}
def action = applicationContext.getBean(controller.fullName).class.declaredFields.find{ field -> field.name == actionName }
if(model && (isControllerApiRenderable(controller) || isActionApiRenderable(action))){
switch(request.format){
case 'json':
render text:model as JSON, contentType: "application/json"
return false
case 'xml':
render text:model as XML, contentType: "application/xml"
return false
default:
render status: 406
return false
}
}
return true
}
В качестве примера, все, что я должен сделать в контроллере для рендеринга xml или json:
@ApiRenderable
def list = {
def collectionOfSomething = SomeDomain.findAllBySomething('someCriteria')
return [someCollection:collectionOfSomething]
}
теперь, если я обращаюсь к URL-адресу, который запускает этот список действий, (/api/0.2/apikey/controller/list.json или /api/ 0.2/apikey/controller/list?format=json или с заголовками: type: application/json), тогда ответ будет закодирован следующим образом:
{
someCollection: [
{
someData: 'someData'
},
{
someData: 'someData2'
}
]
}
Это очень хорошо, если я всегда хочу вернуть hashmap (который в настоящее время является требованием от контроллеров), но в этом примере все, что я хотел вернуть, было фактическим списком! а не список, заключенный в хэш файл....
Есть ли у кого-нибудь указатели на то, как создавать хорошие функциональные возможности api, которые являются надежными и гибкими и которые следуют принципу DRY, которые могут обрабатывать управление версиями (/api/0.1/
, /api/0.2/
) и могут обрабатывать различные сортировки в зависимости от контекста, в котором он возвращается? Любые советы приветствуются!