Simple single class REST server using Java SE only.
- Jave SE 1.6 or above
- No HTTP server / servlet container required
- Uses Java SE socket to listen and process client requests
- Multi-threaded request processing (100 threads by default)
- Uses jackson mapper (org.codehaus.jackson) for JSON processing
- Automatic scanning of all REST resources in current classpath (no configurations required)
Limitations:
- Not a production ready server (for quick REST services testing only)
- supports JSON data communications only
Download or checkout and run following maven command:
$ mvn compile
$ mvn exec:exec -DRESTServer
This command should scan all the classes in current directory for REST resources and listens on 4001 port:
$ mvn exec:exec -DRESTServer
[INFO] Scanning for projects...
...
[INFO] --- exec-maven-plugin:1.3.2:exec (default-cli) @ vjrest ---
INFO: scanning resources...
INFO: Found api: CityResource.delete => /cities/:city
INFO: Found api: CityResource.all => /cities
INFO: Found api: CityResource.create => /cities/new
INFO: Found api: CityResource.update => /cities/:city
INFO: Found api: CityResource.getCity => /cities/:city
INFO: Found api: CityResource.echo => /echo/:str
INFO: Found api: CityResource.getRequestParams => /params
INFO: scanning completed.
INFO: starting server...
INFO: listening on http://localhost:4001
Import static properties from RESTServer class and add @Resource
annotation with path to any POJO (or non-POJO) classes:
import static com.kumarvv.vrest.RESTServer.*;
@Resource("/cities")
public class CityResource {
...
Add @GET
(or @POST, @PUT, @UPDATE
) annotation to the class method. This annotation also supports resource path to append to class resource path.
@GET
public Map<String, City> all() {
...
@GET("favorties") // resolves to "/cities/favorites"
public Map<String, City> favorites() {
return cities;
}
Add @Param
to inject request or url parameter value to method arguments:
@GET(":city")
public City getCity(@Param("city") String cityCode) {
return cities.get(cityCode);
}
Request using /cities/NYC
url will pass the NYC
value to cityCode
method argument.
Add @Data
to inject request payload (form-data) to method argument:
@PUT(":city")
public City update(@Param("city") String cityCode, @Data City upd) {
City city = cities.get(cityCode);
...
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import static com.kumarvv.vrest.RESTServer.*;
/**
* Sample request with full CRUD
*/
@Resource("/cities")
public class CityResource {
private static Map<String, City> cities;
static {
cities = new HashMap<String, City>();
cities.put("NYC", new City("NYC", "New York"));
cities.put("LAX", new City("LAX", "Los Angeles"));
cities.put("SFO", new City("SFO", "San Francisco"));
cities.put("BOS", new City("BOS", "Boston"));
}
@GET
public Map<String, City> all() {
return cities;
}
@GET(":city")
public City getCity(@Param("city") String cityCode) {
return cities.get(cityCode);
}
@POST("new")
public City create(@Data City city) {
city.setCreatedAt(new Date());
cities.put(city.getCode(), city);
return city;
}
@PUT(":city")
public City update(@Param("city") String cityCode, @Data City upd) {
City city = cities.get(cityCode);
if (city != null) {
city.setName(upd.getName());
city.setUpdatedAt(new Date());
cities.put(city.getCode(), city);
return city;
} else {
return null;
}
}
@DELETE(":city")
public String delete(@Param("city") String cityCode) {
cities.remove(cityCode);
return "City [" + cityCode + "] deleted successfully";
}
@GET("/echo/:str")
public String echo(@Param("str") String str) {
return "echo: " + str;
}
@GET("/params")
public Map<String, String> getRequestParams(@Params Map<String, String> params) {
return params;
}
}
This class generates REST resources in following context paths:
GET /cities => maps to CityResource.all()
GET /cities/:city => maps to CityResource.getCity()
POST /cities/new => maps to CityResource.create()
PUT /cities/:city => maps to CityResource.update()
DELETE /cities/:city => maps to CityResource.delete()
GET /echo/:str => maps to CityResource.echo()
GET /params => maps to CityResource.getRequestParams()
Note on /echo/:str
, starting with /
in @GET("/echo/:str")
makes the resource to be at root bypassing the @Resource
annotation at class level. All other resources have /cities
as prefix from @Resource
annotation.
GET request of http://localhost:4001/cities/NYC
will return following json:
{
"code": "NYC",
"name": "New York",
"created": "Sun Jul 18 13:24:12 EDT 2014",
"updated": "Sun Jul 18 13:24:34 EDT 2014"
}