Как использовать строительные леса и RESTfulness вместе в Grails 2.3
Официальная документация Grails гласит, что
Версия 2.0.x плагина для лесов включает в себя различные строительные леса шаблоны, совпадающие с новыми API REST, встроенными в Grails 2.3 и выше. (взято отсюда http://grails.org/doc/latest/guide/scaffolding.html)
Но я не могу сделать (или я не понимаю концепцию) работу RESTfulness вместе с лесами.
Начните с нуля:
grails create-app myapp
cd myapp/
grails create-domain-class Book
grails create-scaffold-controller myapp.Book
Добавить поле в класс домена
class Book {
String text
static constraints = {
}
}
и запустите приложение с помощью grails run-app
.
Серфинг на http://localhost:8080/myapp/
показывает, что строительные леса отлично работают:
-
http://localhost:8080/myapp/book/index
страница показывает список книг
-
http://localhost:8080/myapp/book/show/1
страница показывает подробности для книги с id = 1
-
http://localhost:8080/myapp/book/create
страница создает книгу
- и, следовательно, силы, старые добрые леса.
Посмотрим, что будет с REST.
Официальные документы говорят, что я должен использовать URL-адреса, такие как http://localhost:8080/myapp/books/...
для REST, но любые попытки доступа к приложению, вроде этого curl -i -H "Accept: application/json" localhost:8080/myapp/books/1
возвращает 404 с кучей HTML.
Хорошо, внимательно прочитайте документы:
Самый простой способ создать RESTful API в Grails - выставить класс домена как ресурс REST. Это можно сделать, добавив grails.rest.Resource преобразование в любой класс домена
Нет проблем, теперь заголовок класса книги
import grails.rest.*
@Resource(uri='/books') class Book {
Теперь серфинг на http://localhost:8080/myapp/
показывает, что строительные леса разбиты:
-
http://localhost:8080/myapp/book/index
страница показывает список книг
-
http://localhost:8080/myapp/book/create
отображается страница xml <?xml version="1.0" encoding="UTF-8"?><book><text /></book>
- и так сильно, плохой новый xml-вывод.
Я играл с @Resource и "/books" (ресурсы: "книга" ) в URLMappings.groovy, но не нашел никакого рабочего решения, которое делает возможными строительные леса, а RESTfulness работает спина к спине. Действительно, мне удалось заставить их работать отдельно.
Обновление
Я нашел способ достижения желаемой цели. Я нашел:
- Отметьте класс книги с помощью
@Resource(uri = "/books")
.
- Удалить контроллер леса. BookController.
- Создайте выделенный контроллер с помощью лесов для книги:
class HumanBookController {static scaffold = Book}
Теперь страницы графического интерфейса scaffold с URL-адресами, такими как http://localhost:8080/myapp/humanBook/index
, работают очень хорошо. Любые запросы json обрабатываются с такими URL-адресами, как http://localhost:8080/myapp/books/1
. Но не изящно иметь 2 контроллера, которые делают одинаковые вещи для обычных веб-сайтов и json.
Ответы
Ответ 1
Вы можете сделать это:
import grails.rest.RestfulController
class BookController extends RestfulController {
static responseFormats = ['html', 'json']
BookController() {
super(Book)
}
}
И затем в UrlMappings.groovy:
"/books"(resources:"book")
"/$controller/$action?/$id?(.${format})?"{
constraints {
// apply constraints here
}
}
Не нужно добавлять @Resource в домене.
Теперь у вас есть /books/ 1.json или/books/1.html, чтобы указать на нужные места. Вам может потребоваться сделать grails generate-view Book
для создания представления. Но хотя вам нужно генерировать представления для html, вы сохраняете только один контроллер и путь.
Ответ 2
У меня были те же проблемы, что и у вас.
Это может быть тривиальное решение, а не для каждого случая, но попробуйте обновить версию Grails.
Что касается меня: Grails 2.3.4 → Grails 2.3.6 работал.
Надеюсь, что кто-нибудь поможет.
Ответ 3
В настоящее время я использую Grails 2.4.0, решение получило это:
- Контроллер: BookController {static scaffold = true}
- Домен: Книга {....}//БЕЗ @Resource
В результате вы можете:
- /book.json, чтобы получить список JSONized
- /book/index, чтобы получить стандартные подклассы HTML
- /book/create html scaffold для нового элемента
- /book/show/1 html scaffold edit item 1
- /book/show/1.json JSON для элемента id: 1
Я злой, я знаю. Я нашел этот, и это заставляет меня идти.
Ответ 4
С Grails 2.4.4 мне удалось получить леса, работающие с одним контроллером, используя следующие шаги:
- Добавлен URL-адрес для сопоставления ресурсов в UrlMappings.groovy, например.
"/books"(resources:"book")
- Вставить
static scaffold = true
в сгенерированный контроллер
Я не проверял, изменилось ли следующее, но я также установил grails.mime.disable.accept.header.userAgents = []
и grails.mime.use.accept.header = true
в Config.groovy(последнее, по-видимому, новое значение по умолчанию).
Оба подкласса REST и интерфейсы интерфейса работают нормально со следующими тестами:
- GET/app//1 (передача заголовка Accept)
- GET/app//1.json(нет заголовка Accept)
- POST/app/(с полезной нагрузкой в виде json или формы)
- DELETE/app//1
- PUT/app//1 (с полезной нагрузкой json полезной нагрузки обновил объект, но отправил обратно 302 перенаправления)
ИЗМЕНИТЬ
- Убрал шаг аннотации ресурса и уточнил настройку сопоставления URL
- URI, назначенный в сопоставлении URL, не совпадает с URI по умолчанию для контроллера. Например, "книги" вместо "книги". После добавления этого отображения URI для контроллера по умолчанию будет иметь URI в UrlMapping, но исходный URI будет продолжать работать.
Ответ 5
Сгенерированный контроллер является контроллером Restful, потому что он реализует действия, знакомые с запросами типа:
curl -i -X GET yourDomain:8080/yourApp/books.json
Он возвращает список книг в формате json. (10 книг, предполагая, что вы создали тестовые данные, не так ли?)
Вы можете добавить параметр, например:
curl -i -X GET yourDomain:8080/yourApp/books.xml?40
По умолчанию вы получите формат html
. Вам нужно добавить .json
или .xml
, чтобы получить правильные данные.
Вы также можете использовать заголовок Accept
curl -i -X GET -H "Accept: application/xml" yourDomain/books/1
возвращает детали книги с id = 1 в формате xml. Наконец
curl -i -X POST -H "Content-Type: application/json" -d "{name: 'Book'}" yourDomain/books
создает новую книгу и
curl -i -X PUT -H "Content-Type: application/json" -d "{name: 'Book'}" yourDomain/books/1
обновляет имя книги с id = 1
Все ресурсы должны быть раскрыты через и URL. URL-адрес не создан для вас, вы должны записать его в файл UrlMappings
:
"/v1/books"(resources: "book")
Если первая строка "/v1/books"
- это uri, а вторая строка "book"
- это имя контроллера, следующего за соглашением grails. (Предыдущая строка v1
- это то, что я всегда добавлял номер версии в мои URI API)
| GET | /v1/books | Action: index |
| GET | /v1/books/create | Action: create |
| POST | /v1/books | Action: save |
| GET | /v1/books/${id} | Action: show |
| GET | /v1/books/${id}/edit | Action: edit |
| PUT | /v1/books/${id} | Action: update |
| DELETE | /v1/books/${id} | Action: delete |
Ответ 6
Все, что должно быть необходимо, это аннотация @Resource с uri в классе Domain. Если вам нужны определенные форматы (сначала формат по умолчанию), также включают в себя следующие форматы:
@Resource(uri='/books', formats=['json', 'xml'])
Это должно быть так. Если ypu по-прежнему не удается найти вашу динамическую конечную точку @Resource, попробуйте запустить:
grails url-mappings-report
Это даст вам хорошее резюме всех URL-адресов, включая те, которые поддерживаются контроллерами леса для доменов @Resource. Я обнаружил, что я стараюсь делать глупые ошибки, пытаясь "угадать" URL-адрес - используя вывод отчета, вы гарантируете, что вы и граалы согласны.