Skip to content

ensonik/molecule

 
 

Repository files navigation

Build Status Coverage Status Maven Central License

Issues In Progress

Quick Start

public class HelloWorld {
    public static void main(String[] args) throws IOException {
        WebServer server = WebServer.create();
        server.start((request, response) -> response.done("Hello, World"));
    }
}

Access your application at:

http://localhost:8080

Download

You can get the latest release version from Maven Central:

<dependency>
      <groupId>com.vtence.molecule</groupId>
      <artifactId>molecule</artifactId>
      <version>0.9</version>
</dependency>

If you want the development version, grab the latest snapshot from Sonatype snapshots repositories (https://oss.sonatype.org/content/repositories/snapshots):

<dependency>
      <groupId>com.vtence.molecule</groupId>
      <artifactId>molecule</artifactId>
      <version>0.10-SNAPSHOT</version>
</dependency>

To use the default web server, you also need to add Simple as a dependency:

<dependency>
      <groupId>org.simpleframework</groupId>
      <artifactId>simple-http</artifactId>
      <version>6.0.1</version>
</dependency>

Want to start with some code?

Try out the following examples (Java 6 language level):

Getting Started

First thing first, you need a server to run your app:

WebServer server = WebServer.create();

This will set the default web server, which is powered by Simple, to run locally on port 8080.

To start the server, give it an app:

server.start((request, response) -> response.done("Hello, World!"));

To stop the server, call the stop method:

server.stop()

You can optionally specify the interface and port to bound to when creating the server, e.g. if you want to make your server globally available:

WebServer server = WebServer.create("0.0.0.0", 8088);

Asynchronous Processing

Molecule, uses Simple as a default webserver. Both are fully asynchronous and non-blocking. This allows the server to scale to very high loads and handle as many concurrent connections as possible, even when depending on a high latency external resource.

What this means is you can serve your response content from a thread separate to the original servicing thread. For instance your application might need to wait for some remote process that takes some time to complete, such as an HTTP or SOAP request to an external server. You can simply call this external resource from a different thread, and complete the response when you get the result.

To tell the server that you're ready to serve the response, call the done method on the response (see Asynchronous Processing).

Look at the Asynchronous example to see how to serve content from a separate thread.

Routing

Most modern webapps have nice URLs. Simple URLs are also easier to remember and more user friendly.

Molecule comes with a routing middleware that let you define your URL routes.

Routes let you map incoming requests to different applications based on the request verb and path. A route is composed of a path pattern, an optional set of verbs to match, and an application endpoint:

server.start(new DynamicRoutes() {{
    get("/posts/:id").to((request, response) -> {
        // retrieve a given post
    });
    post("/posts").to((request, response) -> {
        // create a new post
    }); 
    put("/posts/:id").to((request, response) -> {
        // update an existing post
    });
    delete("/posts/:id").to((request, response) -> {
        // delete a post
    }); 
    map("/").to((request, response) -> {
        // show the home page
    });
}});

Matching

Routes are matched in the order they are defined. If not defined route matches, the default behaviour is to render a 404 Not Found. This can be configured to pass the control to any default application.

By default, a route matches a single verb, specified by the method you use, i.e. get, post, put, delete. That can be changed by providing the verbs as arguments to the via method:

map("/").via(GET, HEAD).to((request, response) -> {
    // show the home page
});

If you don't provide any verbs, map will match on all verbs.

Dynamic Parameters

Route patterns can be matched exactly - they are said to be static - or can include named parameters, which are then accessible as regular request parameters on the request object:

// matches "GET /photos/18" and "GET /photos/25"
// request.parameter("id") is either '18' or '25'
get("/photos/:id", (request, response) -> {
    response.done("Photo #" + request.parameter("id"));
});

Custom Matching

You are not limited to the provided match patterns. You can easily implement your own matcher and decide exactly how to match an incoming url to an application.

To do this, use the route definition methods that accept a Matcher rather than a String.

Working with the Request

Request Object

Attributes

Working with the Response

Response Object

Bodies

Redirection and Errors

Cookies

Sessions

Rendering Templates

View Layouts

Testing

Middlewares

Middlewares are a way to enhance your application with optional building blocks, using a pipeline design.

They implement functionality you tend to need across all your applications, but you don't want to build everytime. Things like access logging, authentication, compression, static files, routing, etc.

Being able to separate the processing of the request (and post-processing of the response) in different stages has several benefits:

  • It separate concerns, which helps keep your design clean and application well-structured
  • It let you only include the functionality you need, so your server is as small and fast as possible
  • It let you plug in your own processing stages, to customize the behavior of your application
  • It let you reuse and share middlewares, as elemental building blocks of application behavior

For example you could have the following separate stages of the pipeline doing:

  1. Capturing internal server errors to render a nice 500 page
  2. Monitoring, logging accesses to the server
  3. Authentication and authorisation, to control access to your applicatin
  4. Caching, returning a cached result if request has already been processed recently
  5. Compression, to reduce bandwith usage
  6. Security, to prevent attacks such as CSRF
  7. Processing, to actually process the request

Available Middlewares

Molecule comes with a number of middlewares (more are coming), that you can use to build your processing pipeline:

  • Router (See Routing)
  • Static Assets
  • File Server
  • Access Log
  • Cookies
  • Locale Negotiation
  • Compression
  • ETag
  • Conditional Get
  • Connection Scope
  • Server Header
  • Date Header
  • Content-Length Header
  • Filter Map
  • Cookie Session Tracker
  • Fail Safe
  • Failure Monitor
  • Not Found
  • Http Method Override
  • Layout

About

A micro-framework for easy and fun Java Web Development

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 98.7%
  • Other 1.3%