Giter Site home page Giter Site logo

jooby-project / jooby Goto Github PK

View Code? Open in Web Editor NEW
1.7K 54.0 199.0 70.64 MB

The modular web framework for Java and Kotlin

Home Page: https://jooby.io

License: Apache License 2.0

Java 97.02% HTML 0.20% FreeMarker 0.01% Groovy 0.03% Shell 0.03% Kotlin 1.75% PHP 0.50% Handlebars 0.46% Dockerfile 0.02%
micro-framework web-framework modular kotlin webframework microframework

jooby's Introduction

Maven Central Javadoc Github Slack Discord Become a Patreon Donate

โˆž do more, more easily

Jooby is a modern, performant and easy to use web framework for Java and Kotlin built on top of your favorite web server.

Java:

import static io.jooby.Jooby.runApp;

public class App {

  public static void main(final String[] args) {
    runApp(args, app -> {
      app.get("/", ctx -> "Welcome to Jooby!");
    });
  }
}

Kotlin:

import io.jooby.runApp

fun main(args: Array<String>) {
  runApp(args) {
    get ("/") {
      "Welcome to Jooby!"
    }
  }
}

documentation

Documentation is available at https://jooby.io

help

Slack

donate & support

1.x version

Documentation for 1.x is available at https://jooby.io/v1

Source code for 1.x is available at the 1.x branch

author

Edgar Espina

license

Apache License 2

jooby's People

Contributors

agentgt avatar ajcamilo avatar alladywek avatar angryziber avatar apaulau avatar cmitchell avatar dependabot-preview[bot] avatar dependabot[bot] avatar edgarespinawt avatar extbe avatar feffi avatar franklx avatar froque avatar imeszaros avatar jerouris avatar jknack avatar jschneider avatar jstumpp avatar kevin70 avatar kliushnichenko avatar krisztiankocsis avatar leleuj avatar marcelstoer avatar mdesharnais avatar mrrawbin avatar paul-hammant avatar pierredavidbelanger avatar sentryman avatar tpoll avatar yholkamp 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  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  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

jooby's Issues

support multiple path patterns per route/handler

a common example is to have a create/update handler where the id is optional for create and present for update, something like:

post("/model", "/model/:id", req -> {
  Optional<String> id = req.param("id").toOptional(String.class);
  ...
});

In addition org.jooby.mvc.Path should support multiples patterns too:

@Path({"/model", "/model/:id"})
@GET
public Object createORUpdate(Optional<String> id) {
  ...
}

request should be able to 'seed' requestScoped objects

This issue is related to #32. From request object it should be possible to seed a RequestScoped object:

user("*", req -> {
  req.set(Type.class, new Type());
}

seed method(s) looks like:

  Request set(final Class<?> type, final Object value);

  Request set(final TypeLiteral<?> type, final Object value);

  Request set(Key<?> key, Object value);

import routes from existing App

It should be possible to import/reuse routes from an existing App, for example:

public class A extends Jooby {
  {
    get("/a/1", req -> ...);
  }
}

public class B extends Jooby {
  {
    get("/b/1", req -> ...);
  }
}

public class App extends Jooby {
  {
    use(new A());
    use(new B());
  }
}

App.java contains all the routes from A and B. Also, ONLY routes are imported (modules, parser, formatter, etc.. will be ignored)

When mvn jooby:run add url to the log output

It'd be nice that when you run mvn jooby:run it printed something like:

Listening on: http://127.0.0.1:8080

That way if you have a console that parses output it becomes clickable and you avoid having to type the url in the browser manually.

make the web server pluggable

A web server should be pluggable so in the future Jooby can be package as war and be deployed into a Server Container.

This also will allow to provide multiples server implementation (undertow, netty, jetty, servlets) and let people to choose the best for them

replace jetty with undertow

motivation:

  • extremely lightweight
  • written from scratch (without bad/old design decision and implementation from Servlet API)
  • small API and easy to use
  • no dependency on Servlet API
  • fast bootstrap
  • jar is just 1mb

There are some benchmarks too: http://www.techempower.com/benchmarks/ where undertow seems to perform better than Jetty. Those benchmarks are not the main reason of choosing undertow (reasons were described before). Jetty is a high performance server too.

handle null/missing reason while closing web sockets

ERROR [2014-11-27 11:11:58,264] execution resulted in serious error
java.lang.NullPointerException: A reason is required.
    at java.util.Objects.requireNonNull(Objects.java:228) ~[na:1.8.0]
    at org.jooby.WebSocket$CloseStatus.of(WebSocket.java:160) ~[classes/:na]
    at org.jooby.internal.jetty.JettyWebSocketHandler.onWebSocketClose(JettyWebSocketHandler.java:84) ~[classes/:na]
    at org.eclipse.jetty.websocket.common.events.JettyListenerEventDriver.onClose(JettyListenerEventDriver.java:79) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
    at org.eclipse.jetty.websocket.common.WebSocketSession.notifyClose(WebSocketSession.java:342) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
    at org.eclipse.jetty.websocket.common.WebSocketSession.onConnectionStateChange(WebSocketSession.java:374) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
    at org.eclipse.jetty.websocket.common.io.IOState.notifyStateListeners(IOState.java:185) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]

launch external programs from: mvn jooby:run

useful if grunt (or similar tools) is required in dev environment (development).

<plugin>
  <groupId>org.jooby</groupId>
  <artifactId>jooby-maven-plugin</artifactId>
  <configuration>
    <commands>
      <command>
        <name>npm</name>
        <arguments>
          <argmuent>install</argmuent>
        </arguments>
      </command>
      <command>
        <name>grunt</name>
        <arguments>
          <argmuent>local</argmuent>
        </arguments>
        <wait>false</wait>
      </command>
    </commands>
  </configuration>
</plugin>

A call to: mvn jooby:run will:

  1. run: npm install (blocking, wait = true)
  2. run: grunt local (no blocking, wait = false)
  3. launch the jooby app and block the execution (until Ctrl^C)

Commands section is optional but when present commands will be executed before the jooby app in the order they were provided

webjars support

With the addition of #44 it is pretty straightforward to use http://www.webjars.org/:

assets("/js/**", "/META-INF/resources/webjars/{0}");

GET /js/jquery/2.1.3/jquery.js

Short/custom mapping:

assets("/js/lib/*-*.js", "/META-INF/resources/webjars/{0}/{1}/{0}.js");

GET /js/lib/jquery-2.1.3.js

Add RequestScoped annotation

Implementation of request scoped objects get tricky if we using a child injector per request...

Starting from 0.5.0 Request.Module will be replaced by a RequestScoped annotation (like the servlet module from Guice). But keep in mind jooby won't depends on servlet-module because that will introduce a transitive dependency to the Servlet API.

capturing groups on path vars

support capturing groups on path vars (a.k.a index var)

get("/assets/**", req -> req.vars().get(0)); // /assets/js/jquery.js -> js/jquery.js
get("/:key/:value", req -> req.vars().get(0) + req.vars().get(1)); // /foo/var -> foo:bar

make async-http-client a test dependency

<dependency>
  <groupId>com.ning</groupId>
  <artifactId>async-http-client</artifactId>
</dependency>

vs

<dependency>
  <groupId>com.ning</groupId>
  <artifactId>async-http-client</artifactId>
  <scope>test</scope>
</dependency>

add path and contextPath vars as request locals

These properties should be present in any request by default:

  • path: request path (req.path())
  • contextPath: application path (application.path)

these two vars must be saved as request locals:

assertEquals(req.path(), req.get("path"));
assertEquals(req.require(Config.class).getString("application.path"), req.get("application.path"));

API for converting request params

Introduce a new contract for dealing with param conversions:

interface ParamConverter {
  Object convert(TypeLiteral<?> type, Object[] values, Context ctx);
}

Convert method will be executed every time we try to access a request parameter (either from explicit API or from a MVC handler):

get("/", req -> {
  T value = req.param("myparam").to(T.class);
}

There will be built-in converters for primitives, strings, dates, enums, collections and optionals, but also classes with a public string constructor and/or static methods named: valueOf, fromString, fromName.

Any other new type must be done with a custom param converter:

{
  param((type, values, ctx) -> {
    if (type.getRawType() == T.class) {
      // convert a raw value to T
      return ...;
    }
    // no luck! ask next converter in the chain
    return ctx.convert(type, values);
  });
}

Param converter are executed in the order they were registered. The first param converter that matches/resolved a type wins.

mvc handler doesn't work as expected when a org.jooby.Err is thrown

given:

public class Mvc {

  @GET
  @Path("/")
  public Object handle(Optional<String> value) {
    return value.orElseThrow(()-> new Err(Status.BAD_REQUEST));
  }
}

expected output when value is missing is 400 (bad request) but I got 500 (server error). This only occurs on MVC routes.

Injection for handlebars helpers

let handlebars helper to be injected by Guice:

{
  use(new Hbs().with(Helpers.class));
}

public class Helpers {

  @Inject
  public Helpers(A a) {
    this.a = a;
  }

  public String myHelper() {
    return a.something();
  }
}

Please note isn't require to inject a Helper, simple/small helper can be created easily with the configurer callback:

{
  use(new Hbs().doWith((hbs, config) -> {
    hbs.registerHelper("myhelper", (ctx, options) -> {
      return ...;
    });
    hbs.registerHelpers(Helpers.class);
  });
}

API change: View model must be a Map

Today a view model can be anything:

get("/", View.of("view-name", new Model());

From now on, it must be a Map

get("/", () -> View.of("view-name", "model", new Model());

// or
get("/", () -> {
  Map<String, Object> model = new HashMap<>():
  model.put("model", model);
  return View.of("view-name", model);
});

unable to start two (or more) jdbc data sources

There is a bug while starting two db connection from the jdbc-module.

db = mem
db.audit = mem

The two properties collide each other and the db = mem value is lost.

The correct way of defining two databases will be:

db.main = mem
db.audit = mem

with the following java code:

{
  use(new Jdbc("db.main"));
  use(new Jdbc("db.audit"));
}

convert form urlencoded and multipart/data body as a bean/interface

req params/headers can be injected in any of these classes:

  • interface
public interface Person {
  String name();

  int age();
}
  • class with public constructor
public class Person {
  public final String name;

  public final int age;

  public Person(String name, int age) {
   this.name = name;
   this.age = age;
  }
}
  • class with no-arg constructor
public class Person {
  private String name;

  private int age;

  public String name() {
    return name;
  }

 public int age() {
    return age;
  }
}

retrieval is done using the req.body or req.params method:

// POST or PUT
Person person = req.body(Person.class);

// GET, etc.
Person person = req.params(Person.class);

or from MVC method

    @GET
    public Object params(Person person) {
      ...
    }

  @POST
    public Object body(Person person) {
      ...
    }

add war support

A jooby app should be able to be packaged as a WAR file. This will allow a jobby app to be deployed into a Servlet Container.

War generation will be done by the maven assembly plugin.

Add support for start/stop lifecycle callbacks

Instances of org.jooby.Managed will be started/stopped by Jooby. This mean any Guice o

The Managed.start callback will be executed on every single Guice object, regarless of the scope.

The Manage.stop callback will be executed on Singleton Guice objects, ONLY.

Alternative, any class method annotated with @PostContruct and/or PreDestroy will be supported too.

allow access to request locals from body.writer (write context)

org.jooby.Body.Writer must provides access to request locals (request attributes).

A good example is to allow access to config properties at the rendering phase:

{
  get("*", (req, rsp) -> req.set("config", req.require(Config.class)));
}

Later at rendering stage, we can:

{{config.someProperty}}

API changes on Mutant

rename some methods of Mutant:

req.param("name").stringValue() will be req.param("name").value()
req.param("name").enumValue() will be req.param("name").toEnum(...)

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.