2010-12-07 7 views
116

Wir planen ein Projekt, das hauptsächlich Inhalte für mobile Apps bereitstellt, aber eine Website haben muss.RESTful auf Play! framework

Meine Frage ist, ob es Sinn macht, Jersey oder Restlet zu verwenden, um REST-APIs für unsere mobilen Apps zu entwickeln, und dann Play! um die Website zu bedienen.

Oder macht es mehr Sinn, nur Play zu verwenden! um alles zu machen? Wenn ja, REST mit Play! Rahmen?

+0

i schätzen würde, wenn u können hilf mir hier http://stackoverflow.com/questions/32699420/url-parameters-are-not-being-passed-by-curl-post –

Antwort

25

Verwenden Sie Wiedergabe! um alles zu machen. REST-Dienste in Play schreiben ist sehr, sehr einfach.

Erstens macht es die routes-Datei einfach, Routen zu schreiben, die dem REST-Ansatz entsprechen.

Dann schreiben Sie Ihre Aktionen im Controller für jede API-Methode, die Sie erstellen möchten.

Je nachdem, wie Sie das Ergebnis (XML, JSON usw.) zurückgeben möchten, gibt es einige Methoden, die Sie verwenden können. Wenn Sie beispielsweise die renderJSON-Methode verwenden, können die Ergebnisse sehr einfach gerendert werden. Wenn Sie XML rendern möchten, können Sie dies genauso tun, als würden Sie in Ihrer Ansicht ein HTML-Dokument erstellen.

Hier ist ein nettes Beispiel.

Routen

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 

Anwendungsdatei

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 Datei

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

Ist es möglich, die richtige getUser-Methode basierend auf dem Accept-Header auszuwählen? –

+0

ist es, aber nicht ganz zuverlässig. Wenn play weiß, dass der Header eine JSON-Anfrage ist, wird versucht, eine getuser.json-Datei zu rendern. Wenn der Header ein XML ist, dann versucht es getuser.xml. Es ist jedoch viel einfacher zu verstehen, und mehr REST wie, Benutzer/Benutzer/{ID}/type – Codemwnci

+28

Ich glaube nicht, es ist mehr REST-like, den Darstellungstyp explizit in der URI anzugeben. Es ist besser, den Accept-Header direkt zu verwenden und den URI nicht zu ändern, da die Ressource, die Sie anzeigen möchten, gleich bleibt. Das obige Beispiel könnte so umgeschrieben werden, dass es nur eine einzige getUser-Methode (Long id) hat, die genauso funktioniert wie die aktuelle Implementierung, aber anstatt getUserJSON, getUserXML usw. zu definieren, definieren Sie lieber eine getUser.json- und getUser.xml-Vorlage . Obwohl ich das in user.json/user umbenennen würde.xml zu – seb

5

Integration mit einem JAX-RS Implementierung Datei ist eine mögliche Alternative Ansatz-Spiele-integrierten zu verwenden im HTTP-Routing. Für ein RESEasy-Beispiel siehe RESTEasy Play! module.

Dieser Ansatz ist sinnvoll, wenn Sie bereits in JAX-RS investiert sind oder wenn Sie einige der erweiterten Funktionen benötigen, die JAX-RS bietet, z. B. Inhaltsverhandlung. Wenn nicht, wäre es einfacher, Play direkt zu verwenden, um JSON oder XML als Antwort auf HTTP-Anfragen zu liefern.

112

Wie auf Anfrage, eine einfache REST-Ansatz. Es funktioniert fast genauso wie Codemwncis 'Lösung, verwendet aber den Accept-Header für die Inhaltsverhandlung. Zuerst die Routes-Datei:

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

Hier geben Sie keinen Inhaltstyp an. Dies ist IMHO nur notwendig, wenn Sie "spezielle" URIs für bestimmte Ressourcen haben wollen. Wie erklärt man eine Route zu /users/feed/, um immer in Atom/RSS zurückzukehren.

Der Application Controller sieht wie folgt aus:

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

Wie man sehen kann ich entfernt nur die getUserJSON-Methode und die getUser Methode umbenannt. Damit verschiedene Inhaltstypen funktionieren, müssen Sie jetzt mehrere Vorlagen erstellen. Eine für jeden gewünschten Inhaltstyp. Zum Beispiel:

Benutzer.xml:

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

user.json:

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

USER.HTML:

<html>...</html> 

Dieser Ansatz Browser immer die HTML-Ansicht gibt, da alle Browser senden text/html Inhaltstyp in ihrem Accept-Header. Alle anderen Clients (möglicherweise einige JavaScript-basierte AJAX-Anforderungen) können ihren eigenen gewünschten Inhaltstyp definieren. Mit jQuerys Ajax() -Methode Sie Folgendes tun können:

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

Welche sollten Sie die Details über Benutzer mit der ID 1 im JSON-Format bekommen. Play unterstützt derzeit nativ HTML, JSON und XML, aber Sie können einen anderen Typ verwenden, indem Sie entweder official documentation folgen oder content negotiation module verwenden.

Wenn Sie Eclipse für die Entwicklung verwenden, empfehle ich die REST client plugin, mit der Sie Ihre Routen und den entsprechenden Inhaltstyp testen können.

+2

Danke für das Posten. Das Spiel! Dokumente sind einige der besten, die ich für die Erklärung der grundlegenden Struktur der Dinge gesehen habe, aber manchmal fehlen detaillierte Beispiele. Wenn die beiden Ansätze am selben Beispiel demonstriert werden, wird die Sache wirklich klar. –

+0

Ich probiere Ihr Beispiel aus, ich bin gespannt, wo die geposteten JSON-Daten in Benutzerklasse konvertiert werden. In der createUser-Funktion zum Beispiel finde ich, dass newUser null ist. – Gary

+2

@Gary: Vielleicht haben Sie "Benutzer" anstelle von "NewUser" verwendet? Der Name des Controllers und des Formularparameters müssen übereinstimmen. Ich habe ein einfaches Projekt erstellt, das die obige Methode einschließlich HTML/XML/JSON-Ausgabe für alle Benutzer unter https://github.com/sebhoss/play-user-sample zeigt. – seb

2

Es tut scheint, als wäre dieser Ansatz in Play Version 1.2.3 gebrochen. Wenn Sie die von @seb erstellte und zuvor erwähnte Quelle https://github.com/sebhoss/play-user-sample herunterladen, ist das Erstellen eines neuen Benutzerobjekts mithilfe von POST mit einem JSON-Objekt nicht mehr möglich.

Sie müssen bestimmte Methoden für die Erstellung mit JSON und Xml POSTs verwendet haben. Beschrieben hier: https://groups.google.com/forum/#!topic/play-framework/huwtC3YZDlU

67

Dies ist immer noch eine beliebte Frage, aber die am häufigsten gewählten Antworten sind mit der aktuellen Version des Spiels nicht auf dem neuesten Stand. Hier ist ein Arbeits REST Beispiel mit Spiel 2.2.1:

conf/Routen:

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 
} 
+0

Ich möchte auch eine aktualisierte Version von sebs Antwort sehen, aber leider Ihre Antwort entfernt alle .xml und .html Magie . :-( – flaschenpost