Giter Site home page Giter Site logo

javalin / javalin Goto Github PK

View Code? Open in Web Editor NEW
7.2K 113.0 552.0 4.92 MB

A simple and modern Java and Kotlin web framework

Home Page: https://javalin.io

License: Apache License 2.0

Java 10.63% HTML 0.12% JavaScript 0.02% CSS 0.01% Kotlin 88.95% Vue 0.27% FreeMarker 0.01% Twig 0.01% Mustache 0.01% StringTemplate 0.01%
kotlin java rest-api web-framework microservice servlet jetty javalin hacktoberfest

javalin's Issues

Easier access to request-session

fun sessionAttribute(attribute: String, value: Any) = servletRequest.session.setAttribute(attribute, value)

@Suppress("UNCHECKED_CAST")
fun <T> sessionAttribute(attribute: String): T = servletRequest.session.getAttribute(attribute) as T

@Suppress("UNCHECKED_CAST")
fun <T> sessionAttributeMap(): Map<String, T> = servletRequest.session.attributeNames.asSequence().map { it to servletRequest.session.getAttribute(it) as T }.toMap()

NPE if static-resource folder doesn't exist (or empty?)

[Thread-0] ERROR io.javalin.Javalin - Failed to start Javalin
java.lang.NullPointerException
    at io.javalin.embeddedserver.jetty.JettyResourceHandler.<init>(JettyResourceHandler.kt:29)
    at io.javalin.embeddedserver.jetty.EmbeddedJettyFactory.create(EmbeddedJettyFactory.kt:35)
    at io.javalin.Javalin.lambda$start$1(Javalin.java:74)
    at java.lang.Thread.run(Thread.java:748)
Exception in thread "Thread-0" java.lang.NullPointerException
    at io.javalin.Javalin.lambda$start$1(Javalin.java:83)
    at java.lang.Thread.run(Thread.java:748)

Add tutorial about how to deploy via Docker

Docker containers are perfect for deploying microservices. Instead of deploying to Heroku and then having to pay lots of money when your service becomes popular and you have to scale up and out, or complicated configuration management when manually scaling out your own cloud hosted servers, you can create a simple Dockerfile for your fat jar and a Docker Compose file for running a Docker Swarm cluster.

I didn't test the following, so it's just an example and can be refined in the comments below:

Dockerfile

FROM openjdk:8-jre-alpine

WORKDIR /home
COPY target/my-javalin.jar /my-javalin.jar

EXPOSE 7000

ENTRYPOINT ["java", "-jar", "/my-javalin.jar"]

This can be improved as described here, but is fine for the beginning.

Build Docker image: docker build -t my-name/my-javalin:0.1.0-alpine .

docker-compose.yml

version: "3"

services:

  redis:
    image: redis:3.2-alpine
    ports:
      - "6379"
    volumes:
      - db-data: /data
    networks:
      - libraryapp
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.role == manager]

  my-javalin:
    image: my-name/my-javalin:0.1.0-alpine
    ports:
      - 80:7000
    networks:
      - libraryapp
    depends_on:
      - redis
    deploy:
      mode: replicated
      replicas: 2

networks:
  libraryapp:

volumes:
  db-data:

To run the app on a Docker Swarm cluster: docker stack deploy --compose-file docker-compose.yml my-javalin

When run on a Swarm cluster with one manager and one worker node, this should lead to the redis and one my-javalin container running on the manager node, and one my-javalin container running on the worker node, with automatic load balancing when requests reach either of the two nodes.

Add JSON support to req.bodyParam

As reported in #12, req.bodyParam currently only supports key=value syntax.
Would be neat if it could support JSON.
I don't really want to depend on a library to do this. Would it be good enough it req.bodyParam support 1 level json?

Where is path() ?

The documentation refers to the path() grouping function but I seem to not find it available neither in IDE nor in github master branch. Who is wrong ?

Remove path-param from handlers inside path()?

path("users", () -> { 
    get(UserController::getAllUsers); 
    post(UserController::createUser); 
    path(":id", () -> { 
        get(UserController::getUser);
        patch(UserController::updateUser); 
        delete(UserController::deleteUser); 
    } 
}

Path routing not working

Hey,
I have just been trying out Javalin (with Kotlin) and it's amazing how fast one can build APIs with it!
I just wanted to run my app though and ran into following issue: I have routes with a paths but Javalin does not seem to recognize and route them:

This is part of my code

server.routes {
    path("user") {
        get("login", controller::handleLogin)
    }
}

when opening localhost:port/user/login though, I just get a "Not Found" message and the code in the controller is not called.

If I leave the path away everything is fine.

I would be happy about any tips.

Rewrite methods to include get/set in method names?

Should consider rewriting port(0), enableStaticFiles() etc into setPort(0), setStaticFileLocation("/") etc. This because it would work better with kotlin, and you could do:

val app = Javalin.create().apply {
    port = 0
    staticFileLocation = "/public"
    embeddedServer = ...
}.start()

Groovy sample?

I tried:

@Grapes([
@Grab(group='org.slf4j', module='slf4j-simple', version='1.7.25'),
@Grab('io.javalin:javalin:0.3.7')
])
import io.javalin.Javalin

Javalin app = Javalin.start(7000)
app.get("/") {ctx -> ctx.result("Hello World")}

but it exits immediately... shouldn't it run until ctrl+c?

Websocket timeout on read

How can we adjust the timeout for websocket?

I'm seeing connections erroring out with Timeout on Read which seems to be due to the timeout settings.

Server stuck on Exception

If an error occurs while executing the application logic, then sometimes the server stucks on it. Helps pressing Ctrl-C. Then the server continues to work and processes even those requests that came to it before

Get list of all formParams

In context are many methods to get params map (ctx.paramMap(), ctx.queryParamMap()) ... but I need to get formParamMap() (all fields from x-www-form-urlencoded request) and this method is missing. Can you add this method to context?

Thanks!

Look into ApiBuilder suggestion

@daviddenton makes some suggestions in a gist, which look pretty neat.

Todo:

  • Implement suggestion
  • See how it feels
  • Figure out if/how it will work with Java
// add this method, and verb variants to ApiBuilder...
public static void get(String path, Function<Javalin, Handler> fn) {
    staticInstance().get(prefixPath(path), fn.apply(staticInstance()));
}

// then you can remove the extra methods from ApiBuilder and Javalin which take the overloads

-------------

val myHandler = Handler { it.status(200) }

// this extension function will fix the readability problem IMHO, and add the security behaviour that you want.
fun Handler.securedBy(vararg roles: Role): (Javalin) -> Handler =
    { j -> Handler { ctx -> j.accessManager.manage(this, ctx, roles.toList()) } }

val whatever = path("users") {
    get("/foo", myHandler.securedBy(ApiRole.ANYONE, ApiRole.USER_READ))
}

Describe what differentiates Javalin from other micro web frameworks

Your website currently contains:

Javalin started as a fork of the Spark framework but quickly turned into a ground-up rewrite influenced by express.js.

As a Java developer looking for a simple web framework for a simple RESTful API, not knowing express.js, this doesn't help me a lot. I need to dive into code examples to find out. And what has been rewritten internally?

Add an abstract description or feature list or examples that show the differences.

Is it easier? Faster? Smaller memory-footprint?

Maybe add popular Spring Boot and Dropwizard to the comparison.

HTTP Basic Auth Support

Is HTTP Basic Auth supported yet? The Website Documentation does not mention it yet. Such support would be really great especially since Javalin is all about REST APIs which are often protected by using Basic Authentification.

Any way to convince Jetty instance to hot reload when running via gradle?

I am using Gradle and the kotlin and application plugins to start my Javalin app. I would like to convince Gradle and Jetty to watch and build my code, and hot-reload the Jetty server.

I was hoping that Gradle's "continuous build" feature could be used to trigger rebuilds, and that putting the Jetty server in debug mode might help, but neither of those seem to work. The continuous build seems to be blocked by Jetty taking over the thread, and only works for other commands that "end", such as my unit tests. Perhaps the debug params will only work with the Gradle jetty plugin?

Anyway, I realize this isn't really an issue with Javalin itself, but I was hoping someone in the community might have some insight on how I could improve my Javalin setup to allow for hot-reloads.

Request.bodyParam() return null and cause stacktrace

Hi ! I cloned your sample tipsy/javalin-kotlin-example to try your technology which I found very interesting !

Explanations

After the repo was cloned, I imported the project on IntelliJ (ultimate edition). I ran the project from the Main.kt class and I tried some of the API routes.

All the routes using the GET method work totally fine but the routes which need to parse the request body trigger a stacktrace in the console and the creation or update is aborted.

Those routes doesn't work :

  • http://localhost:7000/users/create
  • http://localhost:7000/users/update/:id

After some debugging, I found that the method bodyParam() in the Request class return null.

Here an example of a request which does not work :

  • route: http://localhost:7000/users/create
  • method: POST
  • body: { "name":"Michel", "email":"[email protected]" }

When I do println(req.body()) at the top of the method, I get this :

{
	"name": "Michel",
	"email": "[email protected]"
}

So, the body is well retrieved in the request !

But when I do println("name="+req.bodyParam("name")+", email="+req.bodyParam("email")), I get :

name=null, email=null

Stacktraces

Here the first stacktrace when we use the alias Request.bp(key: String) setted up at the bottom of the Main.kt file :

java.lang.IllegalStateException: this.bodyParam(key) must not be null
	at app.MainKt.bp(Main.kt:59)
	at app.MainKt$main$$inlined$with$lambda$4.handle(Main.kt:28)
	at io.javalin.core.JavalinServlet.service(JavalinServlet.java:62)
	at io.javalin.embeddedserver.jetty.JettyHandler.doHandle(JettyHandler.java:35)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1568)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.Server.handle(Server.java:564)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:317)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110)
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
	at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:128)
	at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke(Invocable.java:222)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:294)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:199)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
	at java.lang.Thread.run(Thread.java:745)

Then, this is the stacktrace when we use the bodyParam() method :

java.lang.IllegalStateException: req.bodyParam("name") must not be null
	at app.MainKt$main$$inlined$with$lambda$4.handle(Main.kt:28)
	at io.javalin.core.JavalinServlet.service(JavalinServlet.java:62)
	at io.javalin.embeddedserver.jetty.JettyHandler.doHandle(JettyHandler.java:35)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1568)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.Server.handle(Server.java:564)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:317)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110)
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
	at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:128)
	at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke(Invocable.java:222)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:294)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:199)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
	at java.lang.Thread.run(Thread.java:745)

Consider turning `Context` functions into properties

This would lead to a much neater API, and there would be a clear difference between functions and properties. It might affect performance though ๐Ÿค”

Kotlin

Before : headerMap()["Accepts"]
After : headerMap["Accepts"]

Java

Before : ctx.headerMap().get("Accepts")
After : ctx.headerMap.get("Accepts") (if using @JvmStatic )
After : ctx.getHeaderMap().get("Accepts")

Response.body(InputStream)

Being able to connect an InputStream to the response would be very helpful. I've used this regularly in Spark (just returning an InputStream from the handler). Any chance of adding this?

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.