package examples.rest;
import com.vtence.molecule.WebServer;
import com.vtence.molecule.lib.TextBody;
import com.vtence.molecule.middlewares.HttpMethodOverride;
import com.vtence.molecule.routing.DynamicRoutes;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;
/**
* <p>
* This example demonstrates RESTful routing. It shows how to define routes, map routes to HTTP verbs
* and use route patterns containing named parameters.
* </p>
* <p>
* We model a simple music library, with routes to query albums, create new albums,
* update existing albums and finally delete albums. For this simple example we serve plain text responses.
* </p>
* <p>
* We use the {@link HttpMethodOverride} middleware to support PUT and DELETE methods
* using a simple POST with a special <code>_method</code> request parameter.
* </p>
*/
public class RESTExample {
// Our in-memory music library
private final Map<Integer, Album> albums = new TreeMap<>();
// A simple sequence for generating new albums identifiers
private final Sequence sequence = new Sequence();
public void run(WebServer server) throws IOException {
// Support HTTP method override via the _method request parameter
// PUT and DELETE can be done using a POST providing there is a _method
// parameter that describes the actual verb
server.add(new HttpMethodOverride())
.start((new DynamicRoutes() {{
// GET to /albums returns the entire list of albums
get("/albums").to((request, response) -> {
// We server a simple plain text response
TextBody body = new TextBody();
for (int id : albums.keySet()) {
Album album = albums.get(id);
body.append(String.format("%d: %s\n", id, album.info()));
}
if (body.text().isEmpty()) {
body.append("Your music library is empty");
}
response.done(body);
});
// POST to /albums creates a new album
post("/albums").to((request, response) -> {
int id = sequence.next();
Album album = new Album(request.parameter("title"), request.parameter("artist"));
albums.put(id, album);
response.statusCode(201)
.done(album.info());
});
// GET to /albums/<id> fetches an existing album
get("/albums/:id").to((request, response) -> {
int id = Integer.parseInt(request.parameter("id"));
if (albums.containsKey(id)) {
Album album = albums.get(id);
response.done(album.info());
} else {
response.statusCode(404).done();
}
});
// PUT to /albums/<id> updates an existing album
// It can be done with either a PUT or a POST with parameter _method=PUT
put("/albums/:id").to((request, response) -> {
int id = Integer.parseInt(request.parameter("id"));
Album album = albums.get(id);
if (album != null) {
String title = request.parameter("title");
if (title != null) album.title = title;
String artist = request.parameter("artist");
if (artist != null) album.artist = artist;
response.done(album.info());
} else {
response.statusCode(404).done();
}
});
// DELETE to /albums/<id> deletes an existing album
// It can be done with either a DELETE or a POST with parameter _method=DELETE
delete("/albums/:id").to((request, response) -> {
int id = Integer.parseInt(request.parameter("id"));
Album album = albums.remove(id);
if (album != null) {
response.done(album.info());
} else {
response.statusCode(404).done();
}
});
}}));
}
public static class Sequence {
private int next = 1;
public int next() {
return next++;
}
}
public static class Album {
public String title;
public String artist;
public Album(String title, String artist) {
this.title = title;
this.artist = artist;
}
public String info() {
return String.format("Title: %s, Artist: %s", title, artist);
}
}
public static void main(String[] args) throws IOException {
RESTExample example = new RESTExample();
// Run the default web server
WebServer webServer = WebServer.create();
example.run(webServer);
System.out.println("Access at " + webServer.uri() + "/albums");
}
}