RESTful у Play! рамки


117

Ми плануємо проект, в основному розміщуючи вміст для мобільних додатків, але потрібно мати веб-сайт.

Моє питання полягає в тому, чи є сенс використовувати Jersey або Restlet для розробки API REST для наших мобільних додатків, а потім використовувати Play! для обслуговування веб-сайту.

Або має більше сенсу просто використовувати Play! зробити це все? Якщо так, як зробити REST за допомогою Play! рамки?

Відповіді:


112

Відповідно до запиту, простий REST-подібний підхід. Це працює майже так само, як працює рішення Codemwncis, але використовує заголовок Accept для узгодження вмісту. Спочатку файл маршрутів:

GET     /user/{id}            Application.user
POST    /user/                Application.createUser
PUT     /user/{id}            Application.updateUser
DELETE  /user/{id}            Application.deleteUser

Тут ви не вказуєте жодного типу вмісту. Для цього IMHO необхідний лише тоді, коли ви хочете мати "спеціальні" URI для певних ресурсів. Як і оголосити маршрут, щоб /users/feed/завжди повертатися в Atom / RSS.

Контролер програми виглядає приблизно так:

public static void createUser(User newUser) {
    newUser.save();
    user(newUser.id);
}

public static void updateUser(Long id, User user) {
    User dbUser = User.findById(id);
    dbUser.updateDetails(user); // some model logic you would write to do a safe merge
    dbUser.save();
    user(id);
}

public static void deleteUser(Long id) {
    User.findById(id).delete();
    renderText("success");
}

public static void user(Long id)  {
    User user = User.findById(id)
    render(user);
}

Як ви бачите, я лише видалив метод getUserJSON і перейменував метод getUser. Для роботи різних типів вмісту вам доведеться створити кілька шаблонів. По одному для кожного бажаного типу вмісту. Наприклад:

user.xml:

<users>
  <user>
    <name>${user.name}</name>
    . . .
  </user>
</users>

user.json:

{
  "name": "${user.name}",
  "id": "${user.id}",
  . . . 
}

user.html:

<html>...</html>

Цей підхід дає браузерам завжди перегляд HTML, оскільки всі браузери надсилають тип вмісту тексту / html у своєму заголовку Accept. Усі інші клієнти (можливо, деякі запити AJAX на основі JavaScript) можуть визначити власний бажаний тип вмісту. Використовуючи метод jQuerys ajax (), ви можете зробити наступне:

$.ajax({
  url: @{Application.user(1)},
  dataType: json,
  success: function(data) {
    . . . 
  }
});

Що має отримати детальну інформацію про Користувача з ідентифікатором 1 у форматі JSON. Play в даний час підтримує HTML, JSON та XML, але ви можете легко використовувати інший тип, дотримуючись офіційної документації або використовуючи модуль узгодження вмісту .

Якщо ви використовуєте Eclipse для розробки, я пропоную використовувати плагін клієнта REST, який дозволяє перевірити свої маршрути та відповідний тип вмісту.


2
Дякуємо, що опублікували це. Гра! Документи - це одне з найкращих, що я бачив для пояснення основної структури речей, але періодично бракує детальних прикладів. Продемонструвавши два підходи на одному прикладі, справді з'ясовується.
Бред Мейс

Я пробую ваш приклад, мені цікаво, де розміщені JSON дані перетворюються в клас користувача. наприклад, усередині функції createUser я вважаю, що newUser є нульовим.
Гері

2
@Gary: Можливо, ви використовували "user" замість "newUser"? Назва контролера та параметр форми повинні відповідати. Я створив простий проект, який показує вищевказаний метод, включаючи вихід HTML / XML / JSON для всіх користувачів за адресою github.com/sebhoss/play-user-sample
seb

Дякую, я перевірив його, використовуючи curl для надсилання рядка JSON, і, схоже, ігровий фреймворк не розпізнав тип вмісту програми / json: groups.google.com/group/play-framework/browse_thread/thread/…
Gary

@Gary: Дякую за підказку! Здається, це зафіксовано у
головній

68

Це все ще популярне запитання, але відповіді з найвищими голосами не відповідають сучасній версії гри. Ось робочий приклад REST з програмою 2.2.1:

конф / маршрути:

GET     /users                 controllers.UserController.getUsers
GET     /users/:id             controllers.UserController.getUser(id: Long)
POST    /users                 controllers.UserController.createUser
PUT     /users/:id             controllers.UserController.updateUser(id: Long)
DELETE  /users/:id             controllers.UserController.deleteUser(id: Long)

додаток / контролери / UserController.java:

public static Result getUsers()
{
    List<User> users = Database.getUsers();
    return ok(Json.toJson(users));
}

public static Result getUser(Long id)
{
    User user = Database.getUser(id);
    return user == null ? notFound() : ok(Json.toJson(user));
}

public static Result createUser()
{
    User newUser = Json.fromJson(request().body().asJson(), User.class);
    User inserted = Database.addUser(newUser);
    return created(Json.toJson(inserted));
}

public static Result updateUser(Long id)
{
    User user = Json.fromJson(request().body().asJson(), User.class);
    User updated = Database.updateUser(id, user);
    return ok(Json.toJson(updated));
}

public static Result deleteUser(Long id)
{
    Database.deleteUser(id);
    return noContent(); // http://stackoverflow.com/a/2342589/1415732
}

Я також хотів би побачити оновлену версію відповіді seb, але, на жаль, ваша відповідь видалила всі чари .xml та .html. :-(
flaschenpost

26

Використовуйте Play! робити це все. Написати послуги REST в Play дуже просто.

По-перше, файл маршрутів дозволяє легко записувати маршрути, які відповідають підходу REST.

Потім ви записуєте свої дії в контролер для кожного методу API, який ви хочете створити.

Залежно від того, як ви хочете повернути результат (XML, JSON тощо), ви можете скористатися кількома методами. Наприклад, використання методу renderJSON дозволяє рендерувати результати дуже легко. Якщо ви хочете надати XML, ви можете це зробити так само, як ви створили б HTML-документ у своєму представленні.

Ось акуратний приклад.

файл маршрутів

GET     /user/{id}            Application.getUser(format:'xml')
GET     /user/{id}/json       Application.getUserJSON
POST    /user/                Application.createUser
PUT     /user/{id}            Application.updateUser
DELETE  /user/{id}            Application.deleteUser

Файл програми

public static void createUser(User newUser) {
    newUser.save();
    renderText("success");
}

public static void updateUser(Long id, User user) {
    User dbUser = User.findById(id);
    dbUser.updateDetails(user); // some model logic you would write to do a safe merge
    dbUser.save();
    renderText("success");
}

public static void deleteUser(Long id) {
    // first check authority
    User.findById(id).delete();
    renderText("success");
}

public static void getUser(Long id)  {
    User user = User.findById(id)
    renderJSON(user);
}

public static void getUserJSON(Long id) {
    User user = User.findById(id)
    renderJSON(user);
}

файл getUser.xml

<user>
   <name>${user.name}</name>
   <dob>${user.dob}</dob>
   .... etc etc
</user>

Чи можливо вибрати правильний метод getUser на основі заголовка Accept?
Тімо Весткампер

це є, але не зовсім надійно. Якщо гра знає, що заголовок - це запит JSON, він спробує надати файл getuser.json. Якщо заголовок - xml, він спробує отримати getuser.xml. Однак зрозуміти та користуватися користувачем / користувачем / {id} / type
Codemwnci

29
Я не думаю, що більш схожим на REST точно вказати тип представлення в URI. Краще використовувати заголовок Accept безпосередньо і не змінювати URI, оскільки ресурс, який ви хочете бачити, залишається тим самим. Наведений вище приклад може бути переписаний, щоб мати лише один метод getUser (Long id), який точно такий же, як його поточна реалізація, але замість того, щоб визначати getUserJSON, getUserXML тощо, ви краще визначите шаблон getUser.json та getUser.xml. Хоча я би перейменував це на user.json / user.xml теж
seb

Дякую, це дуже корисно. Вдячний за це!
Гері

1
@seb - чи можете ви розгорнути свій коментар у відповідь? Я хотів би побачити приклад методики, яку ви описуєте
Бред Мейс

5

Інтеграція з реалізацією JAX-RS є можливим альтернативним підходом до використання вбудованої HTTP-маршрутизації Play. Для прикладу RESTEasy див. Гру RESTEasy! модуль .

Цей підхід має сенс, якщо ви вже інвестували в JAX-RS або вам потрібні деякі вдосконалені функції REST, які надає JAX-RS, такі як узгодження контенту. Якщо ні, то простіше просто використовувати Play безпосередньо для обслуговування JSON або XML у відповідь на HTTP-запити.



2

Схоже, такий підхід порушено у Play версії 1.2.3. Якщо ви завантажите джерело, зроблене @seb і згадане раніше https://github.com/sebhoss/play-user-sample , створення нового об’єкта користувача за допомогою POST з об’єктом JSON більше не можливо.

Потрібно мати спеціальні методи створення, виконані за допомогою POST json та xml. Окреслено тут: https://groups.google.com/forum/#!topic/play-framework/huwtC3YZDlU

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.