ผ่อนคลายในการเล่น! กรอบ


117

เรากำลังวางแผนโครงการที่ให้บริการเนื้อหาไปยังแอปบนอุปกรณ์เคลื่อนที่เป็นหลัก แต่จำเป็นต้องมีเว็บไซต์

คำถามของฉันคือเหมาะสมหรือไม่ที่จะใช้ Jersey หรือ Restlet เพื่อพัฒนา REST API สำหรับแอปมือถือของเราจากนั้นใช้ Play! เพื่อให้บริการเว็บไซต์

หรือมันสมเหตุสมผลกว่าที่จะใช้ Play! จะทำทั้งหมด? ถ้าเป็นเช่นนั้นวิธีทำ REST ด้วย Play! กรอบ?

คำตอบ:


112

ตามคำขอวิธีง่ายๆเหมือน REST ทำงานเกือบจะเหมือนกับวิธีการแก้ปัญหาของ Codemwncis แต่ใช้ส่วนหัวยอมรับสำหรับการเจรจาต่อรองเนื้อหา ก่อนอื่นไฟล์เส้นทาง:

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 ในส่วนหัวยอมรับ ไคลเอนต์อื่น ๆ ทั้งหมด (อาจเป็นคำขอ AJAX ที่ใช้ JavaScript) สามารถกำหนดประเภทเนื้อหาที่ต้องการได้ ใช้วิธี jQuerys ajax () คุณสามารถทำสิ่งต่อไปนี้:

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

ซึ่งจะทำให้คุณได้รับรายละเอียดเกี่ยวกับ User ที่มี ID 1 ในรูปแบบ JSON เล่นขณะนี้สนับสนุน HTML, JSON และ XML โดยกำเนิด แต่คุณสามารถใช้ชนิดที่แตกต่างกันโดยทั้งต่อไปนี้เอกสารที่เป็นทางการหรือใช้โมดูลการเจรจาต่อรองเนื้อหา

หากคุณใช้ Eclipse สำหรับการพัฒนาฉันขอแนะนำให้ใช้ปลั๊กอินไคลเอ็นต์ RESTซึ่งช่วยให้คุณทดสอบเส้นทางและประเภทเนื้อหาที่เกี่ยวข้อง


2
ขอบคุณสำหรับการโพสต์สิ่งนี้ เล่น! เอกสารเป็นสิ่งที่ดีที่สุดที่ฉันเคยเห็นในการอธิบายโครงสร้างพื้นฐานของสิ่งต่าง ๆ แต่บางครั้งก็ขาดตัวอย่างโดยละเอียด การมีสองวิธีที่แสดงให้เห็นในตัวอย่างเดียวกันจะช่วยล้างสิ่งต่างๆ
Brad Mace

ฉันกำลังลองใช้ตัวอย่างของคุณฉันอยากรู้ว่าข้อมูล JSON ที่โพสต์ถูกแปลงเป็นคลาสผู้ใช้ ตัวอย่างเช่นภายในฟังก์ชัน createUser ฉันพบว่า newUser เป็นโมฆะ
Gary

2
@Gary: บางทีคุณอาจใช้ "user" แทน "newUser"? ชื่อของตัวควบคุมและพารามิเตอร์ฟอร์มต้องตรงกัน ฉันได้สร้างโปรเจ็กต์ง่ายๆที่แสดงวิธีการข้างต้นรวมถึงเอาต์พุต HTML / XML / JSON สำหรับผู้ใช้ทั้งหมดที่github.com/sebhoss/play-user-sample
ก.ย.

ขอบคุณฉันทดสอบโดยใช้ curl เพื่อส่งสตริง JSON และดูเหมือนว่า play framework ไม่รู้จักประเภทเนื้อหาของแอปพลิเคชัน / json: groups.google.com/group/play-framework/browse_thread/thread/…
Gary

@Gary: ขอบคุณสำหรับคำใบ้! ดูเหมือนว่าจะได้รับการแก้ไขในสาขาหลักคุณสามารถลองสร้างด้วยตัวเองแล้วทดสอบอีกครั้ง ..
ก.ย.

68

คำถามนี้ยังคงเป็นคำถามยอดนิยม แต่คำตอบที่ได้รับการโหวตสูงสุดยังไม่เป็นปัจจุบันกับการเล่นเวอร์ชันปัจจุบัน นี่คือตัวอย่าง REST ที่ใช้งานได้กับ play 2.2.1:

conf / เส้นทาง:

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 / ควบคุม / 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 ที่ถูกต้องตามส่วนหัวยอมรับ
Timo Westkämper

มันเป็น แต่ไม่น่าเชื่อถือทั้งหมด หาก play ทราบว่าส่วนหัวเป็นคำขอ JSON ระบบจะพยายามแสดงไฟล์ getuser.json หากส่วนหัวเป็น xml ก็จะลอง getuser.xml อย่างไรก็ตามมันง่ายกว่ามากที่จะเข้าใจและ REST อื่น ๆ เช่นผู้ใช้ / ผู้ใช้ / {id} / type
Codemwnci

29
ฉันไม่คิดว่าการระบุประเภทการเป็นตัวแทนอย่างชัดเจนใน URI จะเหมือนกับ REST มากกว่า จะดีกว่าถ้าใช้ส่วนหัว Accept โดยตรงและอย่าเปลี่ยน URI เนื่องจากทรัพยากรที่คุณต้องการดูยังคงเหมือนเดิม ตัวอย่างข้างต้นสามารถเขียนใหม่ให้มีเมธอด getUser (Long id) เพียงวิธีเดียวซึ่งเหมือนกับการใช้งานปัจจุบัน แต่แทนที่จะกำหนด getUserJSON, getUserXML เป็นต้นคุณควรกำหนดเทมเพลต getUser.json และ getUser.xml แทน แม้ว่าฉันจะเปลี่ยนชื่อเป็น user.json / user.xml ด้วยก็ตาม
ก.ย.

ขอบคุณสิ่งนี้มีประโยชน์มาก ชื่นชมมัน!
Gary

1
@seb - คุณสามารถขยายความคิดเห็นเป็นคำตอบได้หรือไม่? ฉันอยากเห็นตัวอย่างของเทคนิคที่คุณอธิบาย
Brad Mace

5

การผสานรวมกับการใช้งาน JAX-RS เป็นอีกทางเลือกหนึ่งที่เป็นไปได้ในการใช้การกำหนดเส้นทาง HTTP ในตัวของ Play สำหรับตัวอย่าง RESTEasy โปรดดูRESTEasy Play! โมดูล

แนวทางนี้เหมาะสมหากคุณลงทุนใน JAX-RS อยู่แล้วหรือหากคุณต้องการคุณสมบัติขั้นสูงบางอย่าง REST ที่ JAX-RS มีให้เช่นการเจรจาต่อรองเนื้อหา มิฉะนั้นจะง่ายกว่าเพียงใช้ Play โดยตรงเพื่อให้บริการ JSON หรือ XML เพื่อตอบสนองคำขอ HTTP


4

คุณควรดู

http://www.lunatech-labs.com/open-source/resteasy-crud-play-module

มันเป็นโมดูลสำหรับการเล่นที่สร้างส่วนต่อประสานที่เหลือโดยอัตโนมัติเช่นเดียวกับโมดูล crud ที่สร้างพื้นที่ผู้ดูแลระบบโดยอัตโนมัติ ...


2

ดูเหมือนว่าแนวทางนี้จะใช้งานไม่ได้ใน Play เวอร์ชัน 1.2.3 หากคุณดาวน์โหลดซอร์สที่ทำโดย @seb และกล่าวถึงhttps://github.com/sebhoss/play-user-sampleไว้ก่อนหน้านี้การสร้างอ็อบเจ็กต์ผู้ใช้ใหม่โดยใช้ POST ด้วยอ็อบเจ็กต์ JSON จะไม่สามารถทำได้อีกต่อไป

คุณต้องมีวิธีการเฉพาะสำหรับการสร้างโดยใช้ json และ xml POSTs มีรายละเอียดที่นี่: https://groups.google.com/forum/#!topic/play-framework/huwtC3YZDlU

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.