RESTful trên Play! khuôn khổ


117

Chúng tôi đang lên kế hoạch cho một dự án chủ yếu phục vụ nội dung cho các ứng dụng dành cho thiết bị di động, nhưng cần phải có một trang web.

Câu hỏi của tôi là liệu có hợp lý khi sử dụng Jersey hoặc Restlet để phát triển API REST cho các ứng dụng di động của chúng tôi và sau đó sử dụng Play! để phục vụ trang web.

Hay bạn chỉ cần sử dụng Play! để làm tất cả? Nếu vậy, làm thế nào để REST với Play! khuôn khổ?

Câu trả lời:


112

Theo yêu cầu, một cách tiếp cận giống như REST đơn giản. Nó hoạt động gần giống như cách giải pháp của Codemwncis hoạt động nhưng sử dụng tiêu đề Chấp nhận để thương lượng nội dung. Đầu tiên, tệp tuyến đường:

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

Bạn không chỉ định bất kỳ loại nội dung nào ở đây. Làm như vậy IMHO chỉ cần thiết khi bạn muốn có các URI "đặc biệt" cho các tài nguyên nhất định. Giống như khai báo một tuyến đường để /users/feed/luôn trả về trong Atom / RSS.

Bộ điều khiển ứng dụng trông giống như sau:

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);
}

Như bạn có thể thấy, tôi chỉ loại bỏ phương thức getUserJSON và đổi tên phương thức getUser. Để các loại nội dung khác nhau hoạt động, bạn phải tạo một số mẫu. Một cho mỗi loại nội dung mong muốn. Ví dụ:

user.xml:

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

user.json:

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

user.html:

<html>...</html>

Cách tiếp cận này cung cấp cho các trình duyệt luôn ở dạng xem HTML, vì tất cả các trình duyệt đều gửi một loại nội dung văn bản / html trong tiêu đề Chấp nhận của chúng. Tất cả các máy khách khác (có thể là một số yêu cầu AJAX dựa trên JavaScript) có thể xác định loại nội dung mong muốn của riêng họ. Sử dụng phương thức jQuerys ajax () bạn có thể làm như sau:

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

Điều này sẽ cung cấp cho bạn thông tin chi tiết về Người dùng có ID 1 ở định dạng JSON. Play hiện hỗ trợ HTML, JSON và XML nguyên bản nhưng bạn có thể dễ dàng sử dụng một loại khác bằng cách làm theo tài liệu chính thức hoặc sử dụng mô-đun thương lượng nội dung .

Nếu bạn đang sử dụng Eclipse để phát triển, tôi khuyên bạn nên sử dụng plugin ứng dụng khách REST cho phép bạn kiểm tra các tuyến của mình và loại nội dung tương ứng của chúng.


2
Cảm ơn vì đã đăng bài này. Vở kịch! Tài liệu là một số tài liệu tốt nhất mà tôi đã thấy để giải thích cấu trúc cơ bản của mọi thứ, nhưng đôi khi thiếu các ví dụ chi tiết. Có hai cách tiếp cận được chứng minh trên cùng một ví dụ thực sự làm sáng tỏ mọi thứ.
Brad Mace

Tôi đang thử ví dụ của bạn, tôi tò mò về nơi dữ liệu JSON đã đăng được chuyển đổi thành lớp Người dùng. ví dụ, bên trong hàm createUser, tôi thấy newUser là null.
Gary

2
@Gary: Có lẽ bạn đã sử dụng "user" thay vì "newUser"? Tên của bộ điều khiển và tham số hình thức phải khớp. Tôi đã tạo một dự án đơn giản hiển thị phương pháp ở trên, bao gồm đầu ra HTML / XML / JSON cho tất cả người dùng tại github.com/sebhoss/play-user-sample
seb

Cảm ơn, tôi đã thử nghiệm nó bằng cách sử dụng curl để gửi chuỗi JSON và có vẻ như play framework không nhận dạng được ứng dụng / loại nội dung json: groups.google.com/group/play-framework/browse_thread/thread/…
Gary

@Gary: Cảm ơn vì gợi ý! Có vẻ như nó được cố định tại các chi nhánh tổng thể, bạn có thể thử xây dựng nó cho mình và sau đó kiểm tra một lần nữa ..
SEB

68

Đây vẫn là một câu hỏi phổ biến, nhưng các câu trả lời được bình chọn cao nhất không cập nhật với phiên bản chơi hiện tại. Đây là một ví dụ REST đang hoạt động với play 2.2.1:

conf / tuyến đường:

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)

app / controllers / 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
}

Tôi cũng muốn xem phiên bản cập nhật của Câu trả lời của seb, nhưng rất tiếc câu trả lời của bạn đã xóa tất cả phép thuật .xml và .html. :-(
chớp nhoáng

26

Sử dụng Play! để làm tất cả. Viết các dịch vụ REST trong Play rất dễ dàng.

Thứ nhất, tệp định tuyến giúp dễ dàng viết các tuyến phù hợp với cách tiếp cận REST.

Sau đó, bạn viết các hành động của mình, trong bộ điều khiển, cho mỗi phương thức API bạn muốn tạo.

Tùy thuộc vào cách bạn muốn trả về kết quả (XML, JSON, v.v.), có một số phương pháp bạn có thể sử dụng. Ví dụ, sử dụng phương thức renderJSON, cho phép hiển thị kết quả rất dễ dàng. Nếu bạn muốn kết xuất XML, thì bạn có thể làm như vậy giống như cách bạn tạo một tài liệu HTML trong Chế độ xem của mình.

Đây là một ví dụ gọn gàng.

tệp tuyến đường

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

Hồ sơ

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);
}

tệp getUser.xml

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

Có thể chọn đúng phương thức getUser dựa trên tiêu đề Chấp nhận không?
Timo Westkämper

nó đúng, nhưng không hoàn toàn đáng tin cậy. Nếu play biết rằng tiêu đề là một yêu cầu JSON, thì nó sẽ cố gắng hiển thị tệp getuser.json. Nếu tiêu đề là một xml, thì nó sẽ thử getuser.xml. Tuy nhiên, nó là dễ dàng hơn nhiều để hiểu, và REST hơn như thế nào, để người dùng / tài khoản / {id} / loại
Codemwnci

29
Tôi không nghĩ rằng việc chỉ định rõ ràng kiểu biểu diễn trong URI giống REST hơn. Tốt hơn là sử dụng trực tiếp tiêu đề Chấp nhận và không thay đổi URI vì tài nguyên bạn muốn xem vẫn giữ nguyên. Ví dụ trên có thể được viết lại để chỉ có một phương thức getUser (Long id) hoạt động giống hệt như cách triển khai hiện tại của nó nhưng thay vì xác định một getUserJSON, getUserXML, v.v. bạn nên xác định một mẫu getUser.json và getUser.xml. Mặc dù tôi muốn đổi tên đó để user.json / user.xml quá
SEB

Cảm ơn, điều này rất hữu ích. Cảm kích điều đó!
Gary

1
@seb - bạn có thể mở rộng nhận xét của mình thành câu trả lời không? Tôi rất muốn xem một ví dụ về kỹ thuật mà bạn mô tả
Brad Mace 13/12/10

5

Tích hợp với triển khai JAX-RS là một cách tiếp cận có thể thay thế để sử dụng định tuyến HTTP tích hợp của Play. Để biết ví dụ về RESTEasy, hãy xem RESTEasy Play! mô-đun .

Cách tiếp cận này có ý nghĩa nếu bạn đã đầu tư vào JAX-RS hoặc nếu bạn cần một số tính năng nâng cao REST mà JAX-RS cung cấp, chẳng hạn như thương lượng nội dung. Nếu không, sẽ đơn giản hơn nếu chỉ sử dụng Play trực tiếp để phân phát JSON hoặc XML để đáp ứng các yêu cầu HTTP.



2

Có vẻ như cách tiếp cận này đã bị hỏng trong Play phiên bản 1.2.3. Nếu bạn tải xuống nguồn được thực hiện bởi @seb và được đề cập trước đó https://github.com/sebhoss/play-user-sample , thì việc tạo đối tượng người dùng mới bằng cách sử dụng POST với đối tượng JSON sẽ không còn nữa.

Bạn cần có các phương pháp cụ thể để thực hiện bằng cách sử dụng json và xml POST. Được phác thảo tại đây: https://groups.google.com/forum/#!topic/play-framework/huwtC3YZDlU

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.