REST API met Play Framework in Java

1. Overzicht

Het doel van deze tutorial is om het Play Framework te verkennen en te leren hoe je er REST-services mee kunt bouwen met behulp van Java.

We zullen een REST API samenstellen om studentrecords te maken, op te halen, bij te werken en te verwijderen.

In dergelijke toepassingen zouden we normaal gesproken een database hebben om studentrecords op te slaan. Het Play Framework heeft een ingebouwde H2-database, samen met ondersteuning voor JPA met Hibernate en andere persistentiekaders.

Om het echter eenvoudig te houden en ons te concentreren op de belangrijkste dingen, zullen we een eenvoudige kaart gebruiken om studentobjecten met unieke ID's op te slaan.

2. Maak een nieuwe applicatie

Nadat we het Play Framework hebben geïnstalleerd zoals beschreven in onze Inleiding tot het Play Framework, zijn we klaar om onze applicatie te maken.

Laten we de sbt opdracht om een ​​nieuwe applicatie te maken met de naam student-api gebruik makend van play-java-seed:

sbt nieuw speelframe / play-java-seed.g8

3. Modellen

Met onze applicatie-steigers op zijn plaats, gaan we naar student-api / app / modellen en maak een Java-bean voor het verwerken van studentinformatie:

openbare klas Student {private String firstName; private String achternaam; privé int leeftijd; privé int id; // standaard constructeurs, getters en setters}

We gaan nu een eenvoudige gegevensopslag maken - ondersteund door een Hash kaart - voor studentgegevens, met hulpmethoden om CRUD-bewerkingen uit te voeren:

openbare klas StudentStore {privékaart studenten = nieuwe HashMap (); openbaar Optioneel addStudent (Student student) {int id = students.size (); student.setId (id); students.put (id, student); return Optioneel.ofNullable (student); } openbaar Optioneel getStudent (int id) {retourneer Optioneel.ofNullable (students.get (id)); } public Set getAllStudents () {retourneer nieuwe HashSet (students.values ​​()); } openbaar Optioneel updateStudent (Student student) {int id = student.getId (); if (students.containsKey (id)) {students.put (id, student); return Optioneel.ofNullable (student); } retourneer null; } openbare booleaanse deleteStudent (int id) {return students.remove (id)! = null; }}

4. Controllers

Laten we naar toe gaan student-api / app / controllers en maak een nieuwe controller met de naam StudentController.java. We zullen de code stapsgewijs doorlopen.

Ten eerste moeten we configureer een HttpExecutionContext. We implementeren onze acties met behulp van asynchrone, niet-blokkerende code. Dit betekent dat onze actiemethoden terugkeren Voltooiingsfase in plaats van gewoon Resultaat. Dit heeft het voordeel dat we langlopende taken kunnen schrijven zonder te blokkeren.

Er is slechts één voorbehoud bij het omgaan met asynchroon programmeren in een Play Framework-controller: we moeten een HttpExecutionContext. Als we de HTTP-uitvoeringscontext niet leveren, krijgen we de beruchte fout 'Er is vanaf hier geen HTTP-context beschikbaar' bij het aanroepen van de actiemethode.

Laten we het injecteren:

privé HttpExecutionContext ec; privé StudentStore studentStore; @Inject openbare StudentController (HttpExecutionContext ec, StudentStore studentStore) {this.studentStore = studentStore; this.ec = ec; }

Merk op dat we ook het StudentStore en beide velden in de constructor van de controller geïnjecteerd met behulp van de @Injecteren annotatie. Nu we dit hebben gedaan, kunnen we verder gaan met de implementatie van de actiemethoden.

Let daar op Speel schepen met Jackson om gegevensverwerking mogelijk te maken - zodat we alle Jackson-klassen die we nodig hebben kunnen importeren zonder externe afhankelijkheden.

Laten we een utility-klasse definiëren om repetitieve bewerkingen uit te voeren. In dit geval HTTP-reacties opbouwen.

Dus laten we creëren student-api / app / utils pakket en voeg toe Util.java in het:

openbare klasse Util {openbare statische ObjectNode createResponse (Object antwoord, boolean ok) {ObjectNode resultaat = Json.newObject (); result.put ("isSuccessful", ok); if (response instanceof String) {result.put ("body", (String) response); } else {result.putPOJO ("body", antwoord); } resultaat teruggeven; }}

Met deze methode maken we standaard JSON-reacties met een booleaanse waarde is succesvol key en de responsbody.

We kunnen nu de acties van de controller-klasse doorlopen.

4.1. De creëren Actie

In kaart gebracht als een POST actie, zorgt deze methode voor het maken van de Leerling voorwerp:

openbare CompletionStage create (Http.Request-aanvraag) {JsonNode json = request.body (). asJson (); return supplyAsync (() -> {if (json == null) {return badRequest (Util.createResponse ("Expecting Json data", false));} Optioneel studentOptional = studentStore.addStudent (Json.fromJson (json, Student.class )); return studentOptional.map (student -> {JsonNode jsonObject = Json.toJson (student); return created (Util.createResponse (jsonObject, true));}). orElse (internalServerError (Util.createResponse ("Kan niet maken data. ", false)));}, ec.current ()); }

We gebruiken een telefoontje van de geïnjecteerde Http.Request klas om het verzoeklichaam in Jackson's te krijgen JsonNode klasse. Merk op hoe we de utility-methode gebruiken om een ​​reactie te creëren als het lichaam dat is nul.

We retourneren ook een Voltooiingsfase, waarmee we niet-blokkerende code kunnen schrijven met behulp van de VoltooidFuture.supplyAsync methode.

We kunnen er elk overheen gaan Draad of een JsonNode, samen met een boolean vlag om de status aan te geven.

Let ook op hoe we gebruiken Json.fromJson () om het inkomende JSON-object om te zetten in een Leerling object en terug naar JSON voor het antwoord.

Eindelijk, in plaats van OK() wat we gewend zijn, gebruiken we de gemaakt helper-methode van de play.mvc.resultaten pakket. Het idee is om een ​​methode te gebruiken die de juiste HTTP-status geeft voor de actie die binnen een bepaalde context wordt uitgevoerd. Bijvoorbeeld, OK() voor HTTP OK 200-status, en gemaakt () wanneer HTTP CREATED 201 de resultaatstatus is zoals hierboven gebruikt. Dit concept zal tijdens de rest van de acties naar voren komen.

4.2. De bijwerken Actie

EEN LEGGEN verzoek aan // localhost: 9000 / raakt de StudentController.bijwerken methode, die de leerlinginformatie bijwerkt door de updateStudent methode van de StudentStore:

openbare CompletionStage-update (Http.Request-verzoek) {JsonNode json = request.body (). asJson (); return supplyAsync (() -> {if (json == null) {return badRequest (Util.createResponse ("Expecting Json data", false));} Optioneel studentOptional = studentStore.updateStudent (Json.fromJson (json, Student.class )); return studentOptional.map (student -> {if (student == null) {return notFound (Util.createResponse ("Student niet gevonden", false));} JsonNode jsonObject = Json.toJson (student); return ok (Util.createResponse (jsonObject, true));}). OrElse (internalServerError (Util.createResponse ("Kon geen gegevens aanmaken.", False)));}, ec.current ()); }

4.3. De ophalen Actie

Om een ​​student op te halen, geven we de id van de student door als padparameter in een KRIJGEN verzoek aan // localhost: 9000 /: id. Dit zal de ophalen actie:

public CompletionStage retrieve (int id) {return supplyAsync (() -> {final Optional studentOptional = studentStore.getStudent (id); return studentOptional.map (student -> {JsonNode jsonObjects = Json.toJson (student); return ok (Util .createResponse (jsonObjects, true));}). orElse (notFound (Util.createResponse ("Student met id:" + id + "niet gevonden", false)));}, ec.current ()); }

4.4. De verwijderen Actie

De verwijderen actie is toegewezen aan // localhost: 9000 /: id. Wij leveren de ID kaart om te bepalen welk record moet worden verwijderd:

openbare CompletionStage delete (int id) {return supplyAsync (() -> {boolean status = studentStore.deleteStudent (id); if (! status) {return notFound (Util.createResponse ("Student met id:" + id + "niet gevonden ", false));} return ok (Util.createResponse (" Student met id: "+ id +" verwijderd ", true));}, ec.current ()); }

4.5. De listStudents Actie

eindelijk, de listStudents action retourneert een lijst met alle leerlingen die tot nu toe zijn opgeslagen. Het is toegewezen aan // localhost: 9000 / als een KRIJGEN verzoek:

public CompletionStage listStudents () {return supplyAsync (() -> {Set result = studentStore.getAllStudents (); ObjectMapper mapper = new ObjectMapper (); JsonNode jsonData = mapper.convertValue (resultaat, JsonNode.class); return ok (Util. createResponse (jsonData, true));}, ec.current ()); }

5. Toewijzingen

Nadat we onze controlleracties hebben ingesteld, kunnen we ze nu in kaart brengen door het bestand te openen student-api / conf / routes en deze routes toevoegen:

GET / controllers.StudentController.listStudents () GET /: id controllers.StudentController.retrieve (id: Int) POST / controllers.StudentController.create (request: Request) PUT / controllers.StudentController.update (request: Request) DELETE /: id controllers.StudentController.delete (id: Int) GET / assets / * file controllers.Assets.versioned (path = "/ public", file: Asset)

De /middelen endpoint moet altijd aanwezig zijn voor het downloaden van statische bronnen.

Hierna zijn we klaar met het bouwen van het Leerling API.

Ga voor meer informatie over het definiëren van routetoewijzingen naar onze tutorial Routing in Play-toepassingen.

6. Testen

We kunnen nu tests uitvoeren op onze API door verzoeken te sturen naar // localhost: 9000 / en het toevoegen van de juiste context. Het uitvoeren van het basispad vanuit de browser zou moeten resulteren in:

{"isSuccessful": true, "body": []}

Zoals we kunnen zien, is de body leeg omdat we nog geen records hebben toegevoegd. Gebruik makend van krullen, laten we wat tests uitvoeren (als alternatief kunnen we een REST-client zoals Postman gebruiken).

Laten we een terminalvenster openen en het curl-commando uitvoeren naar voeg een leerling toe:

curl -X POST -H "Content-Type: application / json" \ -d '{"firstName": "John", "lastName": "Baeldung", "age": 18}' \ // localhost: 9000 /

Dit zal de nieuw aangemaakte leerling teruggeven:

{"isSuccessful": true, "body": {"firstName": "John", "lastName": "Baeldung", "age": 18, "id": 0}}

Na het uitvoeren van de bovenstaande test, laadt // localhost: 9000 van de browser zou ons nu moeten geven:

{"isSuccessful": true, "body": [{"firstName": "John", "lastName": "Baeldung", "age": 18, "id": 0}]} 

De ID kaart attribuut wordt verhoogd voor elk nieuw record dat we toevoegen.

Naar verwijder een record we sturen een VERWIJDEREN verzoek:

curl -X DELETE // localhost: 9000/0 {"isSuccessful": true, "body": "Student met id: 0 verwijderd"} 

In de bovenstaande test verwijderen we het record dat in de eerste test is gemaakt, laten we nu maak het opnieuw zodat we het bijwerken methode:

curl -X POST -H "Content-Type: application / json" \ -d '{"firstName": "John", "lastName": "Baeldung", "age": 18}' \ // localhost: 9000 / {"isSuccessful": true, "body": {"firstName": "John", "lastName": "Baeldung", "age": 18, "id": 0}}

Laten we nu update het record door de voornaam in te stellen op "Andrew" en de leeftijd op 30:

curl -X PUT -H "Content-Type: application / json" \ -d '{"firstName": "Andrew", "lastName": "Baeldung", "age": 30, "id": 0}' \ // localhost: 9000 / {"isSuccessful": true, "body": {"firstName": "Andrew", "lastName": "Baeldung", "age": 30, "id": 0}}

De bovenstaande test toont de verandering in de waarde van de Voornaam en leeftijd velden na het bijwerken van het record.

Laten we wat extra dummy-records maken, we voegen er twee toe: John Doe en Sam Baeldung:

curl -X POST -H "Content-Type: application / json" \ -d '{"firstName": "John", "lastName": "Doe", "age": 18}' \ // localhost: 9000 /
curl -X POST -H "Content-Type: application / json" \ -d '{"firstName": "Sam", "lastName": "Baeldung", "age": 25}' \ // localhost: 9000 /

Laten we nu alle records bekijken:

curl -X GET // localhost: 9000 / {"isSuccessful": true, "body": [{"firstName": "Andrew", "lastName": "Baeldung", "age": 30, "id": 0 }, {"firstName": "John", "lastName": "Doe", "age": 18, "id": 1}, {"firstName": "Sam", "lastName": "Baeldung", " leeftijd ": 25," id ": 2}]}

Met de bovenstaande test stellen we de goede werking van het listStudents controller actie.

7. Conclusie

In dit artikel hebben we laten zien hoe u een volwaardige REST API kunt bouwen met behulp van het Play Framework.

Zoals gewoonlijk is de broncode voor deze tutorial beschikbaar op GitHub.