Coder Social home page Coder Social logo

jauter's Introduction

Sinetja = Sinatra + Netty + Java

You can use Sinetja with Java 6+. Below examples use Java 8 lambda syntax.

Basic usage

import sinetja.Server;

public class App {
    public static void main(String[] args) {
        Server server = new Server(8000);

        server
            .GET("/", (req, res) ->
                res.respondText("Hello World")
            )
            .GET("/hello/:name", (req, res) -> {
                String name = req.param("name");
                res.respondText("Hello " + name);
            });

        server.start();
        server.stopAtShutdown();
    }
}

req and res are FullHttpRequest and FullHttpResponse with several helper methods to let you extract params and respond.

Javadoc:

Reverse routing

Use server.uri:

import sinetja.Action;

Action helloAction = (req, res) -> {
    String name = req.param("name");
    res.respondText("Hello " + name);
};

server
    .GET("/", (req, res) ->
        res.respondText(
            "URI to Hello World action: " +
            server.uri(helloAction, "name", "World")  // => "/hello/World"
        )
    )
    .GET("/hello/:name", helloAction);

You can also use Map:

Map<String, String> params = new HashMap<String, String>();
params.put("name", "World");
params.put("foo", "bar");
server.uri(helloAction, params);  // => "/hello/World?foo=bar"

Request methods

Common methods: CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, and TRACE.

You can also use ANY, which means the route will match all request methods.

If you want to specify that a route should be matched first or last, use GET_FIRST, GET_LAST etc.

In the example below, /articles/new will be matched before /articles/:id.

server
  .GET      ("/articles/:id", ...)
  .GET_FIRST("/articles/new", ...);

Get request params

Use these methods of Request:

String       param(String name) throws MissingParam
String       paramo(String name)
List<String> params(String name)

param and paramo return a single value. params returns a collection (can be empty) of values (params can be multiple values with same name).

If the request param is missing:

  • paramo will just returns null.
  • param will throw MissingParam. By default, Sinetja will respond error 400 bad request for you. If you want to change the default behavior, you can catch that exception in your action, or at the global error handler (see "500 Internal Server Error" section below).

Order of request param priority: path > body > query. For example, if the routing pattern is /hello/:foo, when request /hello/abc?foo=xyz comes in, param("foo") will return abc.

Respond

Use these methods of Response:

respondText
respondXml
respondHtml
respondJs
respondJsonText
respondJson
respondJsonPText
respondJsonP
respondBinary
respondFile
respondEventSource

All the methods return ChannelFuture.

Async

Thanks to Netty, unlike most Java web frameworks, Sinetja is async. You don't have to respond right away as soon as possible. You can respond later.

Before filter

Java 8 style:

server.before((req, res) -> {
    ...
});

If the filter responds something, the main action will not be called.

After filter

Similar to before filter. It's run after the main action, but before the response is returned to the client. For example, if you want to add a header to all responses, you can do it here.

Log

Sinetja uses SLF4J. Please add an implementation like Logback to your project.

<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.2.2</version>
</dependency>

You can get a logger like this:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyClass {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);
    ...
}

Or if you don't care about the originality of the logger, simply use sinetja.Log:

sinetja.Log.debug("Debug msg");
sinetja.Log.info("Info msg");
sinetja.Log.warn("Warning msg");
sinetja.Log.error("Error msg", error);

404 Not Found

If there's no matched action, Sinetja will automatically respond simple "Not Found" text for you.

If you want to handle yourself:

Java 8 style:

import io.netty.handler.codec.http.HttpResponseStatus;

server.notFound((req, res) -> {
    String uri = req.getUri();
    Log.info("User tried to access nonexistent path: {}", uri);
    res.setStatus(HttpResponseStatus.NOT_FOUND);
    res.respondText("Not Found: " + uri);
});

500 Internal Server Error

By default, Sinetja will automatically respond simple "Internal Server Error" text for you.

If you want to handle yourself:

import io.netty.handler.codec.http.HttpResponseStatus;

server.error((req, res, e) -> {
    Log.error("Error with request: {}", req, e);
    res.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
    res.respondText("Internal Server Error");
});

HTTPS

Use autogenerated selfsigned certificate:

server.jdkSsl();

or (Apache Portable Runtime and OpenSSL libs must be in load path such as system library directories, $LD_LIBRARY_PATH on *nix or %PATH% on Windows):

server.openSsl();

If you want to use your own certificate, use one of these methods:

jdkSsl(String certChainFile, String keyFile)
jdkSsl(String certChainFile, String keyFile, String keyPassword)

openSsl(String certChainFile, String keyFile)
openSsl(String certChainFile, String keyFile, String keyPassword)

The above are utility methods for setting SslContext. If you want to set it directly:

sslContext(SslContext sslContext)

CORS

To tell the server to handle CORS, set CorsConfig:

import io.netty.handler.codec.http.cors.CorsConfig;

CorsConfig config = CorsConfig.withAnyOrigin().build();
server.cors(config);

Stop server

After starting the server, you can stop it:

server.stop();

You can also register a JVM shutdown hook that calls the above automatically:

server.stopAtShutdown();

After the hook has been registered, you can stop the server by running OS command:

kill <PID>

New project skeleton

Discussion mailing list (Google group)

Maven

<dependency>
  <groupId>tv.cntt</groupId>
  <artifactId>sinetja</artifactId>
  <version>1.4.0</version>
</dependency>

You should also add Javassist because it boosts Netty speed:

<dependency>
  <groupId>org.javassist</groupId>
  <artifactId>javassist</artifactId>
  <version>3.21.0-GA</version>
</dependency>

jauter's People

Contributors

ngocdaothanh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

jauter's Issues

Url's with /:* has a bug in the NonorderedRouter.route method

Due to time constraints I downloaded the code and included into my source code to fix a bug when using :* paths. Unfortunately the wrong url with a different root context would be resolved simply because of the wild card.

The bug was on line 109 which had the following:

} else if (!token.equals(token)) {

but should read:

} else if (!currToken.equals(token)) {

Here is the method with the bug fix :

public Routed route(String path) {
final String[] tokens = Pattern.removeSlashAtBothEnds(path).split("/");
final Map<String, String> params = new HashMap<String, String>();
boolean matched = true;

for (final Pattern<T> pattern : patterns) {
  final String[] currTokens = pattern.tokens();
  final T        target     = pattern.target();

  matched = true;
  params.clear();

  if (tokens.length == currTokens.length) {
    for (int i = 0; i < currTokens.length; i++) {
      final String token     = tokens[i];
      final String currToken = currTokens[i];

      if (currToken.length() > 0 && currToken.charAt(0) == ':') {
        params.put(currToken.substring(1), token);
      } else if (!currToken.equals(token)) {
        matched = false;
        break;
      }
    }
  } else if (currTokens.length > 0 && currTokens[currTokens.length - 1].equals(":*") && tokens.length >= currTokens.length) {
    for (int i = 0; i < currTokens.length - 1; i++) {
      final String token     = tokens[i];
      final String currToken = currTokens[i];

      if (currToken.length() > 0 && currToken.charAt(0) == ':') {
        params.put(currToken.substring(1), token);
      } else if (!currToken.equals(token)) {
        matched = false;
        break;
      }
    }

    if (matched) {
      final StringBuilder b = new StringBuilder(tokens[currTokens.length - 1]);
      for (int i = currTokens.length; i < tokens.length; i++) {
        b.append('/');
        b.append(tokens[i]);
      }
      params.put("*", b.toString());
    }
  } else {
    matched = false;
  }

  if (matched) return new Routed<T>(target, false, params);
}

if (notFound != null) {
  params.clear();
  return new Routed<T>(notFound, true, params);
}

return null;

}

abandonded?

I see no traction on this project, is this abandoned? No answers to pull reqs and issues?

Support pattern /articles/:id.:format

"A router" should "handle dots" in {
  val router = new Router[String]
  router.pattern("/articles/:id",         "show")
  router.pattern("/articles/:id.:format", "show")

  val routed1 = router.route("/articles/123")
  routed1.target           should be ("show")
  routed1.params.size      should be (1)
  routed1.params.get("id") should be ("123")

  val routed2 = router.route("/articles/123.json")
  routed2.target               should be ("show")
  routed2.params.size          should be (2)
  routed2.params.get("id")     should be ("123")
  routed2.params.get("format") should be ("json")
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.