javalin / javalin Goto Github PK
View Code? Open in Web Editor NEWA simple and modern Java and Kotlin web framework
Home Page: https://javalin.io
License: Apache License 2.0
A simple and modern Java and Kotlin web framework
Home Page: https://javalin.io
License: Apache License 2.0
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()
[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)
Something like JettyDefaults
app.embeddedServer(
JettyDefaults.sslServer(
keystoreFilePath = "...",
keystorePassword = "..."
)
)
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.
In particular cookie
and header
can be confusing
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?
Currently kotlin-stdlib-jre8 is in the test dependencies section, although it is not marked as one. For reference
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 ?
path("users", () -> {
get(UserController::getAllUsers);
post(UserController::createUser);
path(":id", () -> {
get(UserController::getUser);
patch(UserController::updateUser);
delete(UserController::deleteUser);
}
}
On the form of:
ctx.headers.accept
Could also provide more helpful fields, like
ctx.headers.authorization.basic
or even ctx.headers.authorization.basic.username
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.
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()
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?
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.
Hello. Thanks for the server!
Is there way to make live-reload for directory with static files for rapid developemnt? It would be great
This should be fine for now:
object Jackson {
fun configure(staticObjectMapper: ObjectMapper) {
objectMapper = staticObjectMapper
}
}
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
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!
@daviddenton makes some suggestions in a gist, which look pretty neat.
Todo:
// 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))
}
Are there built-in integration tests?
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.
I ported the project to Kotlin in #11.
Would be very helpful if a Kotlin programmer could have a look.
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.
https://github.com/awaitility/awaitility
doHandle {
AsyncContext asyncContext = request.startAsync();
CompletableFuture.runAsync(() -> {
try {
javalinServlet.service(cachedRequest, response);
} catch (IOException | ServletException e) {
throw new RuntimeException(e);
}
}).thenAccept((Void) -> {
jettyRequest.setHandled(true);
asyncContext.complete();
});
}
^^^ Pointless?
https://wiki.eclipse.org/Jetty/Feature/Continuations#Using_Continuations
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.
Hi ! I cloned your sample tipsy/javalin-kotlin-example to try your technology which I found very interesting !
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 :
http://localhost:7000/users/create
POST
{ "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
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)
Before : headerMap()["Accepts"]
After : headerMap["Accepts"]
Before : ctx.headerMap().get("Accepts")
After : ctx.headerMap.get("Accepts")
(if using @JvmStatic
)
After : ctx.getHeaderMap().get("Accepts")
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?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.