close
Ginger Docs v1.1.2
open

Ginger

Ginger is a opinionated Resource Routing framework applied on top of Spark. One of the goals for Ginger is to be as simple as possible to get started with, yet flexible enough to extend as needed. Ginger may not be right for everyone. Ask your developer if Ginger is right for you.

Set Up

It’s important to note that since Ginger is heavily tied to Spark, we only support Java8 (as is the case with Spark). You can add Ginger to your project by adding it to your build.gradle file, as a dependency.

compile 'com.bradcypert.Ginger:1.1.2'

Setting up a Resource

Ginger is broken up into two separate pieces - ginger.Model and ginger.Resource. The Model defines what the RESTful Resource should look like, and the Resource reflects upon that model, to generate your routes for you.

Let’s go ahead and write a simple Model. In the spirit of elementary programming, we’ll make a Todo list.

import com.bradcypert.ginger.Exposed;
import com.bradcypert.ginger.Model;
import com.bradcypert.ginger.Methods;
import com.bradcypert.ginger.PropertyMap;

@Methods
public class Todo implements Model {
    @Exposed public String name;
    @Exposed public int id;
    public boolean finished;

    @Exposed private double someNumber;

    @Override
    public String save(PropertyMap map) {
        return "{\"somejazz\": \"jazz\"}";
    }

    @Override
    public String fetch(String id) {
        return "{\"name\": \"Work Out\", \"completed\": false}";
    }

    @Override
    public String fetchAll() {
        return "[{\"name\": \"Work Out\", \"completed\": false}, {\"name\": \"Sleep in\", \"completed\": true}]";
    }

    @Override
    public String remove(String id) {
        return "{\"deleted\": true}";
    }
}

There’s quite a few things going on here, so let’s cover them in detail. First off, we’re importing the parts of the Ginger framework that we need. The next thing you’ll notice, is the @Methods annotation. @Methods tells the model that it’s going to support GET, POST, and DELETE HTTP verbs. The ginger.Resource (that’ll we’ll write in a moment) reads this to determine which routes to generate. If, for example, you only wanted to support GET, and POST, you could write the following: @Methods(value={"GET", "POST"}).

NOTE: Support for more HTTP verbs coming soon.

Next, you’ll noticed that our class implements ginger.Model. This interface is necessary to be implemented as the Resource requires the interfaces methods to exist. Those methods are the ones with the @Override annotation tied to them.

Here’s a simple mapping of what routes map to which Model Methods.

GET     /todo/       => fetchAll()
GET     /todo/:id/   => fetch()
POST    /todo/       => save()
DELETE  /todo/:id/   => remove()

The last thing to note about the Model is the @Exposed tag. Any member variables tagged with @Exposed will be REQUIRED to be sent in on a POST request. For example, in the Java code above, our POST route has to either have query or body params of name, id, and someNumber. If these parameters are not there, the server will return a 400 error code.

It’s important to keep in mind that your Model is actually just a template. Long term data shouldn’t be stored in the model, as Ginger will destroy and create instances of it, as it sees fit. What this means is simple - The methods save, fetch, fetchAll, and remove should be fully state-independent. Here is where you would plug in your ORM or execute SQL Queries or whatever you need to do.

Activating a Resource

Once you’ve declared a model, like we did above, the final step is simple. From your main entry point, you can simply write:

//import com.bradcypert.ginger.Resource;

Resource todos = new Resource(Todo.class);
todos.generateRoutes();

This will generate all the required routes for your Model, and plug them into Spark (the routing framework that is used under the covers). Once your code runs, you should be able to hit localhost:4567/todo/ in your browser and get a list of your Todos.

Deep Dive

So now that you’ve seen the basics of setting up a Ginger service, let’s take a deep dive into the actual docs for the classes provided. If you can’t find what you’re looking for here, I strongly recommend checking out Spark’s Documentation as Ginger uses Spark under the hood.

Resource

The Resource is the main code generator in Ginger. The Methods are as follows.

public Resource(Class clazz)

The constructor is called to set up the initial resource. You need to pass in the class of an object that implements the ginger.Model interface.

Code Example:

Resource todos = new Resource(Todo.class);
public void generateRoutes()

Generate routes needs to be called before you can actually use the routes provided. Generally, you’ll see something like this.

new Resource(Todo.class).generateRoutes();

This will generate all the applicable routes based on your @Methods declaration in your Model.

public Object getInstance()

Returns the instance of the model created by the Resource. If you need to access anything on your model class outside of normal routing, you probably want to call this method to get ahold of the instance.

Todo instance = (Todo) new Resource(Todo.class).getInstance();

This will generate all the applicable routes based on your @Methods declaration in your Model.

public void setBasePath(String path)

setBasePath will prepend a string onto the routes for the resource. For example:

Resource todos = new Resource(Todo.class);
todos.generateRoutes();

The above example will generate, for example, localhost:4567/todo/.

Perhaps, you want to prepend /api/v1 to the resource. You can do so with the following.

Resource todos = new Resource(Todo.class);
todos.setBasePath("/api/v1");
todos.generateRoutes();

Property Map

Currently, the Property Map class is a minimal extension on Java’s HashMap, that simply implementes a custom constructor.

public PropertyMap(spark.Request request, List mappings)

The constructor simply takes in a spark.Request and a List of strings. These strings are then iterated over, and the associated params are pulled out and stored on the underlying HashMap object. Odds are, you probably won’t NEED this class, and can simply treat it like a HashMap whenever you see it being used.

request     =>    spark.Request object
mappings    =>    List of Strings that you'd like to pull from the map.