Coder Social home page Coder Social logo

nubes's Introduction


⚠️ tl;dr: don't use this repository, use something like Quarkus instead. ⚠️

Unfortunately, this project relies on an old version of Vert.x. Upgrading it to Vert.x 3.5 requires a lot of work, I am looking at it, but since it's a "weekend" project, it might take months. Sorry for the inconvenience. Obviously any kind of help would be greatly appreciated. Thank you for your comprehension.

If you feel like you want to help, any pull request would be highly welcomed. You can also fork the project, and start working on your own stuff, with your own vision of what such an annotation framework would be to suit your needs. The license allows you to do so.

You can start by forking the project, changing Vert.x dependency to 3.5 get it to compile (which requires some work) then run the tests (there's a pretty good code coverage) and start fixing stuff from there. That's probably the best way to help.

As an alternative, you can have a look at Quarkus, which adds JAX-RS annotation capabilities on top of Vert.x (with a lot of other interesting modules).

Special thanks to johnfg10 for upgrading to 3.5.2.


Build Status Codecov

Vert.x Nubes

Provides an annotation layer on top of vertx-web.

Declare your Vert.x routes with annotated methods and controllers, in a Spring MVC-ish way.

repositories {
  jcenter()
}

dependencies {
  compile 'com.github.aesteve:nubes:2.0'
}

Declarative

Nubes automatically injects method parameters at runtime so that you can express your routes in a declarative manner. By reading the signature of the method, you should be able to have a quick glimpse at what your route uses (query parameters, request body, ...) and produces (void => status 204, object => marshalled).

public PeanutsCharacter get(@Param CharacterType type) lets us know that the method uses a request parameter named type and that the response will contain a marshalled PeanutsCharacter POJO.

Nubes comes with a controller layer, but also a service layer. You can declare services as simple POJOS and they'll be injected within your controllers, you can also declare your services as async, they'll be started when your application starts, stopped when the application stops.

Extensible

The framework is designed to be fully extensible so that you can register and use your own annotations, whether it's an interceptor, a type-adapter, ...

A good example on how to extend the framework is Nubes Mongo, a set of additionnal utilities (annotations, interceptors, ...) designed to help you deal with Mongo on top of Nubes. For example, nubes-mongo registers a @Create annotation against Nubes framework, meaning that the result of the method should be saved against the Mongo database.

Basically, an annotation will be tied to a set of Vert.x's Handlers, executed before and/or after the 'route' method is executed.

Non-blocking (obviously) but also non-stumbling

Even though Nubes looks opinionated (declaring your routes in a single way : the controller/method way), keep in mind that at the end of the day, vertx-web's router is still there and fully accessible if you find yourself stuck in an edge case Nubes isn't designed to handle. This way, you should never, ever be stucked.

You just have a set of additional utilities at your disposal to declare your web routes in another way (a SpringMVC-ish way), to declare and inject services if you don't have a DI framework at your disposal, or to write Verticles differently.

The Router can also be injected as a field within your controllers as an easy way to deal with it, and maybe register routes at runtime if you need to.

Examples

(Work in Progress)

If you're interested in how a real-life project built with Nubes would look like, you can have a look at Nubes Chat a very simple chat relying on a REST API and Vert.x's event-bus bridge which shows both REST and Socket controllers in action. On top of that, it uses a MongoDB as a persistent store so you can get a nice view of the service layer.

Basic example :

A controller :

package com.peanuts.controllers;

@Controller("/peanuts")
public class PeanutsPages {
  
  public ENUM CharacterType {
    DOG, GIRL, BOY, BIRD;
  }
  
  @GET("/character")
  @View
  public String getCharacter(@ContextData Map<String, Object> data, @Param CharacterType type) {
    switch(type) {
      case DOG: 
        data.put("name", "Snoopy");
        break;
      case BOY:
        data.put("name", "Charlie Brown");
        break;
      // ...
    }
    return "character.hbs";
  }
}

The view :

web/views/character.hbs

<html>
  <body>
    Hello, I'm a Peanuts character, and my name is {{name}}
  </body>
</html>

GET "/peanuts/character?type=DOG" will return the following html view:

Hello, I'm a Peanuts character, and my name is Snoopy

A JSON api example

package com.peanuts.controllers;

@Controller("/api/1/peanuts")
@ContentType("application/json")
public class CharactersController {
  
  @Service("mongo")
  private MongoService mongo;
  
  @GET("/character")
  public PeanutsCharacter getCharacter(@Param CharacterType type) {
    switch(type) {
      case DOG: 
        return new PeanutsCharacter(CharacterType.DOG, "Snoopy", snoopysBirthDate);
      // etc. 
    }
  }
  
  @POST("/character") // declaring RoutingContext as parameter means your method is async
  public void createCharacter(RoutingContext context, @RequestBody PeanutsCharacter character) {
    mongo.save(character, handler -> {
      context.next();  
    }); // save it using JDBC service, mongo service, hibernate service, etc.
  }
}

With this an example of domain object :

package com.peanuts.model;

public class PeanutsCharacter {

  public ENUM CharacterType {
    DOG, GIRL, BOY, BIRD;
  }

  private CharacterType type;
  private String name;
  private Date birthDate;
  
  // getters, setters, constructors and stuff
}

GET "/api/1/peanuts/characters?type=DOG" with an Accept header containing application/json will return :

{
  "name":"Snoopy",
  "type":"DOG",
  "birthDate":"1950-11-04T08:00:00.000Z"
}

POST "/api/1/peanuts/characters" with the following request body :

{
  "name":"Snoopy",
  "type":"DOG",
  "birthDate":"1950-11-04T08:00:00.000Z"
}

Will save our favorite cartoon dog into the database, then return an HTTP 204.

How it works

VertxNubes as the entry point

The entry point of every work with the framwork is creatning a VertxNubes instance.

You'll notice the constructor takes two arguments :

  • a Vertx instance
  • a JsonObject containing the configuration

Please take a look at the configuration documentation for the available, mandatory or not, options.

Once you've created the VertxNubes instance, you need to bootstrap it. What it's gonna do is scanning your application classes (annotated with @Controller) in order to create the approriate Web routes/handlers and attach it to a vertx-web Router.

You can provide your own Router, if you want to to add custom routes and stuff in the standard vertx way.

You can also let VertxNubes instanciate a Router. It's gonna return it to you once it's done bootstrapping. And you'll be able to do pretty much whatever you need with it.

VertxNubes nubes = new VertxNubes(vertx, config);
nubes.bootstrap(res -> {
  if (res.succeeded()) {
    Router yourRouter = res.result();
    System.out.println("Everything's ready");
  } else {
    System.err.println("Something went wrong");
    res.cause().printStackTrace();
  }
});

You'll find a ton of examples in the tests of the project.

If you take a look at the mock controllers, you'll pretty much find everything that's possible to do with Nubes out of the box.

The Controller layer

What is a @Controller ?

A controller is a Java singleton (per Nubes instance) defining a set of methods which will be translated into vertx-web handlers. (~= express middlewares).

It's important that your controller defines a no-argument constructor, VertxNubes expect that.

In a controller you'll find routes, annotated with @GET, @POST, @PUT, ... but also filters of two differents types : @BeforeFilter and @AfterFilter.

For each route in your controller, before filters will be executed before your actual route method, and after filters, well... after.

Annotations

Nubes provides some default annotations. Here's the list.

But you can also define your own annotations, and attach vertx-web handlers to it.

In this case, you can register what Nubes calls "Annotation processors" which will be called before, after (or both) your method is invoked.

Nubes itself registers its own annotations using this API. For example, the @ContentType({"application/json", "application/xml"}) annotation is bound to a ContentTypeProcessor which will :

  • check the Accept header of the request, and if it doesn't matches the MIME type you're handling, return a 406 status to the client
  • find the most suitable MIME among the ones the client specified in its Accept header and the ones you specified in the body of the ContentType annotation
  • inject this ContentType as a variable in the RoutingContext so that you can also benefit from it
  • position the Content-Type response header so that you don't have to care about it

Read the annotations document

Parameters

Parameters are automatically injected into every method at runtime, depending on the context of the request (parameters, body, ...).

For a complete list of available parameters (by default), see the parameters documentation.

But you can also register your own parameter resolvers by telling nubes : "When you find this type of parameter, resolve it like this".

Parameters can be resolved simply by their types (that's how Nubes injects the RoutingContext or the EventBus parameters if your method asks for it) or by a custom annotation you define.

Read the parameters injection documentation

The View Layer

TODO : explain that template engines are created by the user, and bound to a file extension. Then how views are resolved, either by @View("viewName.extension") or through the ViewResolver parameter.

The Service Layer

Services in Nubes are simple POJOs you register on the Nubes instance using nubes.registerService(String name, Object serviceInstance). This way, you'll be able to access them from your controllers using the @Service("someName") annotation.

Standard services

Any POJO can be a service. Simply register it against Nubes.

Async services

In some case, services take time to startup or to be closed. If you want your service to be started when Nubes bootstraps, just implements Nubes Service interface and register it, the same way you would register a POJO.

RPC and service proxies

TODO : Explain how to use vertx's service proxy.

SockJS

Nubes provides a simple way to declare SockJS handlers with annotations instead of handlers defined in vertx-web.

For example, to handle incoming sockets you would do the following.

@SockJS("/sockjs/*")
public class SockJSController {
  @OnMessage
  public void onMessage(SockJSSocket emitter, Buffer message) {
    emitter.write(Buffer.buffer(message)); // simply echo the message back
  }
}

You can also use vertx-web's event-bus bridge if you want your users to access some addresses over the event-bus from client-side using SockJS.

@EventBusBridge("/sockjs/*")
@InboundPermitted("some-allowed-address")
public class BridgeController {

  @SOCKET_CREATED
  public void whenSocketIsCreated(BridgeEvent event) {
    // do what you want...
  }
  
  @REGISTER
  public void whenSomeUserRegisters(BridgeEvent event) {
    // do what you want...
  }
  
}

nubes's People

Contributors

aesteve avatar brasseld avatar darekxan avatar johnfg2610 avatar ldallen avatar morteza 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

nubes's Issues

Add defaults ErrorHandler

And provide a way to map them on a specific content-type

In VertxMVC :

router.failureHandler(failureHandlerRegistry)

FailureHandlerRegistry :

public void handle(RoutingContext context) {
    String contentType = context.get("best-content-type");
    PayloadMarshaller marshaller = marshallers.get(contentType);
    if (marshaller == null) {
        defaultErrorHandler.handle(context); // displays an html error page
    } else {
        marshaller.marshallError(context.failure());
    }
}

And in PayloadMarshaller interface, add a marshallError(Throwable t) method.

And add the implementation into JSONPayloadMarshaller.

Also, provide a configuration option to tell the framwork to include stacktraces in errors or not.

Create static handler

Convention over configuration

By default, the static handler should be a assets folder in project's root directory, containing 3 subdirectories : scripts, img, stylehseets.

setDirectoryListing to false

Test throttling

  • No throttling if no annotation
  • 420 returned when too many requests sent
  • Wait then retry : no 420
  • Requests on non-throttled paths are not counted

Add fixtures

How do user provide fixtures ?

They should just implement an interface with two single methods that deal with domain objects.

  • setup(Vertx vertx)
  • tearDown(Vertx vertx)

User is responsible for creating and saving their domain objects, (since we can't do it for them, because of cascade relationships etc.)

In conf.json, the user should specify wich fixtures are run.

"fixtures" : [
    "com.mycompany.fixtures.fixtures.MyUsers",
    "com.mycompany.fixtures.fixtures.MyAccessRoles"
]

Then in VertxMVC.bootstrap() scan for fixtures through vertx.config() and execute them.

Handle redirects

  1. Client redirect (easy)
  2. Server redirect (forward) : that's the hard part : should merge one route onto another

ViewResolver

@View("nameoftheview") is nice but limited.

Sometimes the view name will be dynamic.

So provide a ViewResolver parameter user can add to their method to set the name of the view. dynamically (i.e. if(somethingWenWrong) { resolver.resolve("failure.hbs") } )

Increase code coverage

See jacocoTestReport for more infos :

Errors

NotFound, Validation, ... And also RuntimeException marshalling in

  • json
  • xml
  • plainText
  • http status (context.fail(400) in XML)

DateUtils

  • unit tests (with TimeZone)

PaginationContext

Wrong configuration

  • the right error is thrown at startup (or use Objects.requireNonNull)

User-defined stuff :

  • register custom param adapter and test it's called / used
  • his own failure handler is called
  • his own auth method is called
  • register adapter
  • registerAnnotatedParamInjector
  • his own locale resolver is called
  • add paramHandler

Test NubesServer

Services

  • wrong method parameters => error should be thrown at bootstrap, not during runtime
  • periodic task method with parameters

Param injection

  • no cookie set => 400
  • get Cookie object, not cookie value
  • RequestBody : throw exceptions instead of returning null ? + test JsonObject + test JsonArray
  • Params : test 400 if wrong params / Param (same) / Header (same)
  • Headers : not a multimap => 500
  • LocalMap : by param name (no annotation value)
  • EventBus
  • HttpServerRequest
  • User locale
  • ResourceBundle

Http methods

  • CONNECT
  • TRACE
  • HEAD

Processors

  • NoopAfterAllProcessor is not used, use it in a custom-defined Processor (see above)
  • CheckAuthority with no user set => 401
  • CheckToken (auth) with wrong formated auth data => 400
  • RoutingContext failed before method is invoked (in filter, ...)

Integ. testing on AsyncUtils

  • nextOrFail(context)
  • onFailureOnly
  • onSuccessOnly
  • failOr(context)

Auth

  • JWT
  • redirect with no redirectURL => breaks at bootstrap not at runtime

EventBusBridgeFactory / SocketFactory

  • path with /path/* but also with /path and /path/
  • Vertx injected as method param
  • controller can't be instanciated => error at startup, not at runtime (same for standard controllers)

RouteFactory

  • filters from superclass are executed

VerticleFactory

  • @InheritsConfig => the config is inherited properly

Injection

  • Fields from superclass are injected (or filters from superclass)

TemplateEngineManager

  • no template handler found => should throw an exception and test it

Current coverage : 1918 / 7957 76 %
Current coverage : 1 427 of 7 959 82 %
Current coverage : 1 124 of 7 998 86 %

Facility for handling FileUploads

@StoreTo(path) ? or something like that.

For now, let users deal with since it can be done manually using Apex.

But think about a set of annotations to deal with file uploads.

View support should change to be same as JSON marshalling result, with view annotation

Having views add to a data bag isn't allowing using concrete view objects at the top level. And why not just make it identical to how you would do JSON/XML marshalling for a REST call. You return an object, and if there is a @View("viewname") annotation it hands the returned object to the view as the model.

Then you can have one method which can have a view when accepts is set to html, and not run the view when they ask for JSON from the same method.

@View("viewname", "contenttype") says when the view is triggered. Maybe something else that allows the JSON or XML marshalling to trigger such as @ContentType("application/json") on the method. could be combined:

@ContentType("text/xhtml", view="myviewnmae")
@ContentType("application/json")
public SomeDataClass myMethod() {...}

sets two content types, a view for one of them, and just straight marshalling to JSON for the other.

something along these lines...

or internal framework has a debug mode that allows you to &format=json on any view method to get the model instead as JSON. On the controller or method we allow debug mode to be on or off for that scope, and debug mode itself is controlled either by securely adding the flag into the session for internal users, or always on in dev mode.

Create NubesVerticle

Relying directly on config so that it's more convenient to start a NubesServer (if user doesn't care about the router).

Use CompletableFuture

Since the project is Java only, we can make intensive use of CompletableFuture and especially allOf and join.

Keep that in mind and replace MultipleFuture and stuff.

(btw see vertx-feeds for a better implementation of MultipleFuture)

Is Boon a safe option, we have had VM crashes caused by Boon

Is Boon a safe option? Here is my opinion: no.

For speed optimizations the code makes assumptions about internal class layouts, arrays, etc and doing simple things as a custom deserializer caused Java VM crashes. And that library brings in all sorts of errant utilities.

It has code in JsonFastParser that says it might cause memory leaks, so at least avoid that parser.

Also look in the code for things like:

@SuppressWarnings ( { "unchecked", "SuspiciousSystemArraycopy" } )

We found odd things creating a custom Joda datetime serializer that did very little, but plug it in, serialize, VM crash.

Search the code for where and how sun.unsafe is used to directly access the body of strings. Now take a JVM language which wraps string, hand it to those and see if you get a loud Boom. And how does that affect Open JDK usage?

https://github.com/boonproject/boon/blob/1b741669e7fc1a64afdc342cdb4bb7359c995b94/boon/src/main/java/org/boon/core/reflection/FastStringUtils.java

If the string is wrapped by something (which some languages do), the value offsets become -1 which cause pointer math to go off into unknown space. The code doesn't handle that at all and no-ops on field not found in the wrapper.

Boon gets extra speed from unsafe things. We got sick of the crashes, and never went back to try again.

Parameters injection

For now, we only have the RoutingContext as parameter but, an interesting feature would be to outbox and convert parameters for the end-users and inject it to the method.

Like : public void search(RoutingContext context, SearchCriteria criteria) where criteria is instanciated from request parameters.

First implementation possible, let user define their class by implementing an interface : fromRequestParams(MultiMap ... blah)` then provide some utility methods upon that.

Provide Mixins

Allow users to compose their controllers with mixins so that they can reuse logic.

For example, they could declare a LoggingMixin this way :

@Mixin("log")
public class LogMixin {
    @Before
    public void timeBefore(RoutingContext context) {
        context.put("timeBefore", System.currentTimeMillis());
        context.next();
    }

    @After
    public void logAfter(RoutingContext context) {
        long timeAfter = System.currentTimeMillis();
        long timeBefore = Long.valueOf(context.get("timeBefore"));
        logger.info("time for request #0", timeAfter - timeBefore);
        context.next();
    }
}

Then in MyApiController :

@Controller("my/api")
@Includes("log")
public class MyApiController {
    @GET
    public void myApi(RoutingContext context, Payload<String> payload) {
         payload.set("Hello");
         context.next();
    }
}

ViewController

Tests :

  • Create test templates of each type
  • call render() for each template file
  • assert it's OK

Provide an EventBusBridge

@SockJS controllers could be annotated with @EventBusBridge to act as an eventbus bridge for Javascript clients.

See : http://vertx.io/docs/vertx-web/java/#_sockjs_event_bus_bridge

Problem is : the security options for the bridge, which are specified in vertx-web thanks to PermittedOptions for both the inbound and outbound traffic.

How to map these permitted options and address / regex matching onto an annotation ?

Probably use several annotations like :

@SockJS("/eventbus/*")
@EventBusBridge
@InboundPermitted("echo.*")
@OutboundPermitted("*")
public class MyBridge {
}

i18n

Provide everything so that i18n is straightforward to deal with for end-users.

This means : a bundles directory out of src/main/resources so that bundles can be hot-reloaded in a dev environment.

But package bundles into the application in other environments.

Plus : Provide i18n utilities for every template engine.

Run tests with two different configurations

  • Run tests the normal way with VertxNubesTestBase
  • Run tests with NubesServerTestBase

Maybe we could do that with Junit @Rule

For now NubesServer is out of the test scope, which is unwanted.

@ServiceProxy(String) & @Proxify(String)

Service proxies are a great feature of Vert.x 3

  1. When an interface is marked as @ProxyGen, a class is generated by the compiler to communicate through the event bus. But still, we have to create the code to mount it to a specific eventBus address.
  2. Another interface is generated to access the service on a specific address remotely.

Examples :

  1. https://github.com/aesteve/vertx-markdown-service/blob/master/src/main/java/io/vertx/markdown/MarkdownServiceVerticle.java#L17
  2. https://github.com/aesteve/vertx-markdown-service/blob/master/src/test/java/io/vertx/markdown/eventbus/GenerateThroughEventBusTest.java#L36

It would be very convenient to add two annotations to cover these use cases :

  1. The interface could be annotated with @Proxify("some.address") which would automatically look for the generated class, instanciate it and mount it like here
  2. Instead of @Service for dependency injection, we could just add @ServiceProxy("some.address") which would inject the proxified service into some class

improve readme

i noticed the readme lacks the instructions like how to get the nubes, how to run the server etc. I didn't find nubes from maven or anywhere. vertx-jersey has a good starter guide here: https://github.com/englishtown/vertx-jersey i was almost going with that until i noticed how terrible their api is compared to yours. to get more hype, starting with the framework has to be as easy as possible so more people would give it a try :)

Generalize the API

  1. provide on VertxMVC :
  2. registerClassAnnotation(Annotation annotation, Handler<RoutingContext> handler)
  3. registerMethodAnnotation(Annotation annotation, Handler<RoutingContext> handler)
  4. Use them for @UsesCookies, @Throttled, ...
  5. Make ParameterAdapter an interface
  6. provide registerParameterAdapter(Class<?> clazz, ParameterAdapter adapter)
  7. if it does match use it, else defaults to DefaultParameterAdapter

@CSRF

Rely on vert-x3/vertx-web#155

  • create an annotation @CSRF(String)
  • create an annotation processor using the value of the CSRF annotation

Maybe this could lead to new mechanisms in Nubes.

Provide utilities on Vertx client

Since Boon is already used for marshalling, it could be costless to provide a layer on top of vertx.createClient() to wrap BodyHandler and directly map it onto a Java object.

Maybe something like :

jsonRequest<T>(Vertx vertx, AsyncResult<T> async ->
    // async failure contains an exception or status code, ...
    // async.result() is the unmarshalled object ?
)};

Refactor the VertxMVC class

For now, everything we do in VertxMVC is blocking (reflection stuff).

In the future (see #4 ) there could be async stuff => VertxMVC should return Future<Void>, especially if users bootstrap from their own verticle.

Also, keep the reflection stuff and route reflection discovery out of this class. This class should only be a conductor for every kind of bootstrapping stuff :

  • routes by reflection
  • template handlers instantiation
  • database / ORM startup/config (if we implement the model layer)
  • loading fixtures
  • ...

=> it needs to be refactored properly (and create a package named bootstrap)

eventbus and services

Hi !
I'm trying to build some small examples with nubes, and I would like to be able to communicate with a client through the eventbus.
I just created an echo service which reply every message received at "service.echo" address on the eventbus, and I tried to send a message to the same address on the client side, but it's not working.. In fact, the message sent by the client is received correctly by the SockJSController, but the service never receive it.
Is it something not implemented yet, or did I forget to add some configuration ?

L-M

Integrate authentication

OAuth / Oauth2 through annotations for API requests

@Authentication annotation on controller methods + provide Apex's way to handle authentication

Provide a way to order filters

@BeforeFilter(order=1)
public void executedFirst(RoutingContext context) {
}

@BeforeFilter(order=2)
public void executedThen(RoutingContext context) {
}

=> when adding filter handlers, respect orders or just reorder the list once every filter has been discovered, but before Apex routes are created

Test pagination

Write tests :

  • PaginationContext reflects the request parameters when asked by user in controller
  • Pagination links are provided in response when user sets nbTotalResults

MarkdownTemplateEngine

Maybe it can be useful ? It's costless anyway, simply use pegdown.

No inheritance / composition etc. but :

  • provide some kind of placeholder for injecting context.data() variables, maybe {{myVariable}}
  • add a way (programmatic ? or in template ?) to specify some stylesheets for markdown styling
  • wrap markdown directly into body, but generate a proper html template

Not sure it's useful.

Refactor Cookie handling

Existing now :

@UsesCookie
public void myMethod(RoutingContext context) {
  routingContext.getCookie("bleh");
}

That's probably not consistent with dependency injection used everywhere else.

Keep this annotation if some user just wants to set a cookie but won't read any (and rename it @SetsCookie ?)

Moreover provide another annotation :

public void myMethod(@Cookie("myCookie") Cookie cookie)

If the parameter type is Cookie then simply inject context.getCookie(annotation.value()) else if it's a String inject context.getCookie(annotation.value())?.value()

Error loading jaxb.index

Hi !

I don't know if it's just with my computer, but when I try to start the nubes tests, I got some error like this :
"mock.domains" doesnt contain ObjectFactory.class or jaxb.index
If I comment the line which loads the domain package, I can run the tests (90/94 passed).
Is it an issue or just intelliJ ?

Use RXJava ?

In order to replace MultipleFutures and maybe some other stuff.

Should method names be considered as paths ?

( Should we add more convention over configuration )

Example for an ApiController :

OrdersApiController would be mapped on apiMountPoint/orders its getMyOrders method would then be mapped on GET apiMountPoint/orders/myorders

If and only if the method is public and note annotated as a filter.

Example for a ViewController :

CartViewController would be mapped on /cart and its getMyCart method would be mapped on GET /cart/mycart.

Test @RequestBody

Standard request body parsing (same as @Params ) and using Boon in case of a JsonApi

Provide a pipeline API

What is a pipeline ?

It's a way to transform resources either at runtime (dev environment) or at startup or at build time (and then the framework doesn't care).

We could offer a pipeline API which would associate a resource to its built equivalent and map it to one single path. And then would transform it or not dependeing on the context.

Example

If we're on a dev environment :

When the user asks for assets/*.css, look for web/styles/*.scss, then send invoke my transform function and return the result.

If we're on a production environment :

Look for every file in web/styles/*.scss, if you fin their equivalent into dist/styles/*.css then it's OK, serve directly those files when assets/*.css is asked. If some are missing, please invoke my transformation function and save the result.

Pretty complicated to explain, not that easy to implement, but very useful.

Handle sync methods

When a route is very simple calling context.next() every time could be a pain (not to mention users will forget when they don't do async stuff).

So, if the method doesn't declare a RoutingContext parameter, call context.next() programatically once the method has returned.

User method parameter names instead of requiring @param or pathparam type annotations

Java 8, Kotlin, and others have parameter name information available for methods. So @Param("from") from: Int us redundant. Vert.x is Java 8 or higher. Although Java 8 requires you compiling with parameter names turned on.

For languages like Kotlin you could have a plugin return the names of parameters for you if you don't want to figure out how to do that. Same plugin model could support Java 8.

Or since you have annotations, you could use annotation processing to write out the property names at compile time to a resources file you use. Another option, although not all other JVM languages might support annotation processing. I think Paranamer does this already, https://github.com/paul-hammant/paranamer.

I note that Jackson JSON processor has support for plugins that do all the models above.

Service injection

Just like fixtures, provide a service interface.

Instanciate services and inject them into controllers when bootstrapping.

Handle return parameters

At least for sync methods ( #21 ) : when a method doesn't use the RoutingContext (so that we're sure context.next() is not called before returning ??)

Dependeing on the controller class we could do different stuff.

In an APIController we'll marshall the return type, or just prepare response if it's a String, or a JsonObject,

In a ViewController we'll assume that's the view name if it's a String.

Rename project

... And find a name.

Candidates :

  • caelum (sky in latin)
  • supra ("on top of" in latin)
  • nubes (clouds in latin)

Since Apex means summit in Latin, and the framework runs on top of Apex, the only things that remain are either the sky, or maybe the clouds.

Different approaches to look at :

  • transverse
  • introspective
  • extract ( estrep )
  • construct
  • detach, explode ( explosio)
  • adapt ( adatt )
  • transpose ( transpon )

Routing DSL

Maybe a Groovy DSL (routing file) could be something interesting to look at (in complement of annotations) :

routes {
    "/dogs/:dogId" {
        GET "com.peanuts.dogs.DogController.getDog",
        POST "com.peanuts.dogs.DogController.createDog"
    } // ...
}

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.