/jesi

Hypermedia API Accelerator

Primary LanguageGoMIT LicenseMIT

Jesi - a hypermedia API accelerator

Jesi (stands for JSON Edge Side Include) is an HTTP reverse proxy that accelerates your web API by embedding & caching JSON representations.

Getting Started

Install Jesi from GitHub Releases (pick a binary for your platform):

$ curl -L https://github.com/ichiban/jesi/releases/download/v0.2.0/jesi-darwin-amd64 > jesi
$ chmod +x jesi

Then, run it with your backend server:

$ ./jesi -backend http://localhost:3000 -port 8080

Features

Embedding

Jesi understands JSON Hypertext Application Language aka HAL+JSON and can construct complex HAL+JSON documents out of simple HAL+JSON documents from the upstream server. By supplying a query parameter ?with=<edges> with dot separated edge names, it embeds HAL+JSON documents linked by _links as _embeded. (This functionality is also known as zooming)

This will decrease the number of round trips over the Internet which is crucial for speeding up web API backed applications.

Caching

Jesi implements HTTP Caching described in RFC 7234. Every representation including but not limited to HAL+JSON documents is cached and served from the cache on behalf of the upstream server while it's fresh.

Combined with embedding, the resulting HAL+JSON representation is constructed from cached representations and representations newly fetched from the upstream server so that it can maximize cache effectiveness.

When Jesi cache reaches the memory limitation specified by -max command line option, it evicts some cached representations with LRU algorithm.

Example

Let's consider an example of a movie database app. It has resources of a movie Pulp Fiction, roles Vincent Vega and Jules Winnfield, and actors John Travolta and Samuel L. Jackson.

{
  "_links": {
    "self": {"href": "/movies/1"},
    "roles": [{"href": "/roles/1"}, {"href": "/roles/2"}]
  },
  "title": "Pulp Fiction",
  "year": 1994
}
{
  "_links": {
    "self": {"href": "/roles/1"},
    "actor": {"href": "/actors/1"},
    "movie": {"href": "/movies/1"}
  },
  "name": "Vincent Vega"
}
{
  "_links": {
    "self": {"href": "/roles/2"},
    "actor": {"href": "/actors/2"},
    "movie": {"href": "/movies/1"}
  },
  "name": "Jules Winnfield"
}
{
  "_links": {
    "self": {"href": "/actors/1"},
    "roles": [{"href": "/roles/1"}]
  },
  "name": "John Travolta"
}
{
  "_links": {
    "self": {"href": "/actors/2"},
    "roles": [{"href": "/roles/2"}]
  },
  "name": "Samuel L. Jackson"
}

They're connected by _links property - a movie has many roles and a role has exactly one actor.

Movies

To render a view for Pulp Fiction, it has to make requests for the movie /movies/1 and also /roles/1, /roles/2, /actors/1, and /actors/2 for the details. By making a request /movies/1?with=roles.actor, Jesi responds with one big HAL+JSON document with the roles and actors embedded in the movie JSON.

{
  "_links": {
    "self": {"href": "/movies/1"},
    "roles": [{"href": "/roles/1"}, {"href": "/roles/2"}]
  },
  "_embedded": {
    "roles": [
      {
        "name": "Vincent Vega",
        "_links": {
          "self": {"href": "/roles/1"},
          "actor": {"href": "/actors/1"},
          "movie": {"href": "/movies/1"}
        },
        "_embedded": {
          "actor": {
            "name": "John Travolta",
            "_links": {
              "self": {"href": "/actors/1"},
              "roles": [{"href": "/roles/1"}]
            }
          }
        }
      },
      {
        "name": "Jules Winnfield",
        "_links": {
          "self": {"href": "/roles/2"},
          "actor": {"href": "/actors/2"},
          "movie": {"href": "/movies/1"}
        },
        "_embedded": {
          "actor": {
            "name": "Samuel L. Jackson",
            "_links": {
              "self": {"href": "/actors/2"},
              "roles": [{"href": "/roles/2"}]
            }
          }
        }
      }
    ]
  },
  "title": "Pulp Fiction",
  "year": 1994
}