JRestless

JRestless allows you to create serverless applications using JAX-RS.

Build Status codecov GitHub issues GitHub closed issues License

SonarQube: SonarQube - Quality Gate SonarQube - Coverage SonarQube - Bugs SonarQube - Vulnerabilities SonarQube - Tests SonarQube - Duplicated Blocks SonarQube - Technical Debt SonarQube - Code Smells

Table of Contents

Description

JRestless is a framework allowing you to build serverless JAX-RS applications or rather to run JAX-RS applications in FasS (Function as a Service) environments like AWS Lambda. This is achieved by providing a generic Jersey container that handles requests in the form of POJOs. For each FaaS environment there is a separate module acting as an integration layer between the actual environment and the generic Jersey container.

Since this framework is just a wrapper around or rather a container for Jersey, you can use almost all JAX-RS features plus Jersey's custom extensions like Spring integration - not Spring MVC, though since this functionality is provided by JAX-RS itself.

Supported Environments:

Motivation

The motivation for this project is to avoid a cloud vendor lock-in and to allow developers to run and test their code locally.

Features

Function Types

AWS

Fn Project

Note: the framework is split up into multiple modules, so you choose which functionality you actually want to use. See Modules

Usage Example

AWS Usage Example

All examples, including the following one, can be found in a separate repository: https://github.com/bbilger/jrestless-examples

JRestless does not depend on the serverless framework but it simplifies the necessary AWS configuration tremendously and will be used for this example.

Install serverless (>= 1.0.2) as described in the docs https://serverless.com/framework/docs/guide/installing-serverless/

Setup your AWS account as described in the docs https://serverless.com/framework/docs/providers/aws/guide/credentials/

Create a new function using serverless

mkdir aws-gateway-usage-example
cd aws-gateway-usage-example
serverless create --template aws-java-gradle --name aws-gateway-usage-example
rm -rf src/main/java # remove the classes created by the template
mkdir -p src/main/java/com/jrestless/aws/examples # create the package structure

Replace serverless.yml with the following contents:

service: aws-gateway-usage-example-service

provider:
  name: aws
  runtime: java8
  stage: dev
  region: eu-central-1

package:
  artifact: build/distributions/aws-gateway-usage-example.zip

functions:
  sample:
    handler: com.jrestless.aws.examples.RequestHandler
    events:
      - http:
          path: sample/{proxy+}
          method: any

Replace build.gradle with the following contents:

apply plugin: 'java'

repositories {
  jcenter()
  mavenCentral()
}
dependencies {
  compile(
    'com.jrestless.aws:jrestless-aws-gateway-handler:0.6.0',
    'org.glassfish.jersey.inject:jersey-hk2:2.26',
    'org.glassfish.jersey.media:jersey-media-json-jackson:2.26'
  )
}
task buildZip(type: Zip) {
  archiveName = "${project.name}.zip"
  from compileJava
  from processResources
  into('lib') {
    from configurations.runtime
  }
}
build.dependsOn buildZip

Create a new JAX-RS resource and a response object (src/main/java/com/jrestless/aws/examples/SampleResource.java):

package com.jrestless.aws.examples;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/sample")
public class SampleResource {
  @GET
  @Path("/health")
  @Produces({ MediaType.APPLICATION_JSON })
  public Response getHealthStatus() {
    return Response.ok(new HealthStatusResponse("up and running")).build();
  }
  static class HealthStatusResponse {
    private final String statusMessage;
    HealthStatusResponse(String statusMessage) {
      this.statusMessage = statusMessage;
    }
    public String getStatusMessage() {
      return statusMessage;
    }
  }
}

Create the request handler (src/main/java/com/jrestless/aws/examples/RequestHandler.java):

package com.jrestless.aws.examples;

import org.glassfish.jersey.server.ResourceConfig;

import com.jrestless.aws.gateway.GatewayFeature;
import com.jrestless.aws.gateway.handler.GatewayRequestObjectHandler;

public class RequestHandler extends GatewayRequestObjectHandler {
  public RequestHandler() {
    // initialize the container with your resource configuration
    ResourceConfig config = new ResourceConfig()
      .register(GatewayFeature.class)
      .packages("com.jrestless.aws.examples");
    init(config);
    // start the container
    start();
  }
}

Build your function from within the directory aws-gateway-usage-example:

gradle build

This, amongst other things, creates a deployable version of your function (build/distributions/aws-gateway-usage-example.zip) using the dependent task buildZip.

Now you can deploy the function using serverless:

serverless deploy

If serverless is configured correctly, it should show you an endpoint in its output.

...
endpoints
  ANY - https://<SOMEID>.execute-api.eu-central-1.amazonaws.com/dev/sample/{proxy+}
...

Hit the endpoint:

curl -H 'Accept: application/json' 'https://<SOMEID>.execute-api.eu-central-1.amazonaws.com/dev/sample/health'
# {"statusMessage":"up and running"}

Fn Project Usage Example

A very good example of how to use JRestless on Fn Project can be found here: https://github.com/fnproject/fn-jrestless-example

Modules

JRestless is split up into multiple modules whereas one has to depend on the *-handler modules, only. jrestless-aws-gateway-handler is probably the most interesting one.

All modules are available in jcenter.

Alternative Projects

AWS

Limitations

AWS

Fn Project

Release History

CHANGELOG

Meta

License

Distributed under Apache 2.0 license. See License for more information.