I created this years ago and I'm no longer actively working with java. If anyone is interested maintaining this (and has experience with java), feel free to leave a comment here. It merely was a proof-of-concept of how we could do things more the "funcional" oriented way and less like big java-frameworks and library use to be (as seen on simple but extremely popular libraries such as expressjs).
Expressapp = newExpress();
app.get("/", (req, res) -> {
res.send("Hello World");
}).listen(); // Will listen on port 80 which is set as defaultAdd the following dependency coordinate from JCenter on your favorite build system:
io.vacco.java-express:java-express:<VERSION>
Express allows the attaching of request-handler to instance methods via the DynExpress annotation:
// Your main classimportexpress.Express;
publicclassMain {
publicstaticvoidmain(String[] args) {
Expressapp = newExpress();
app.bind(newBindings()); // See class belowapp.listen();
}
}
// Your class with request handlersimportexpress.DynExpress;
importexpress.http.RequestMethod;
importexpress.http.request.Request;
importexpress.http.response.Response;
publicclassBindings {
@DynExpress() // Default is context="/" and method=RequestMethod.GETpublicvoidgetIndex(Requestreq, Responseres) {
res.send("Hello World!");
}
@DynExpress(context = "/about") // Only context is defined, method=RequestMethod.GET is used as methodpublicvoidgetAbout(Requestreq, Responseres) {
res.send("About page");
}
@DynExpress(context = "/impressum", method = RequestMethod.PATCH) // Both definedpublicvoidgetImpressum(Requestreq, Responseres) {
res.send("Impressum page was patched");
}
@DynExpress(method = RequestMethod.POST) // Only the method is defined, "/" is used as contextpublicvoidpostIndex(Requestreq, Responseres) {
res.send("POST to index");
}
}You can add routes (And middlewares) directly to the Express object to handle requests:
Expressapp = newExpress();
// Sample for home routesapp.get("/", (req, res) -> res.send("Hello index!"));
app.get("/home", (req, res) -> res.send("Homepage"));
app.get("/about", (req, res) -> res.send("About"));
// Sample for userapp.get("/user/login", (req, res) -> res.send("Please login!"));
app.get("/user/register", (req, res) -> res.send("Join now!"));
app.listen();Directly it also supports methods like POSTPATCHDELETE and PUT, others need to be created manually:
Expressapp = newExpress();
// Basic methodsapp.get("/user", (req, res) -> res.send("Get an user!"));
app.patch("/user", (req, res) -> res.send("Modify an user!"));
app.delete("/user", (req, res) -> res.send("Delete an user!"));
app.put("/user", (req, res) -> res.send("Add an user!"));
// Example fot the CONNECT methodapp.on("/user", "CONNECT", (req, res) -> res.send("Connect!"));
app.listen();But it's better to split your code, right? With the ExpressRouter you can create routes and add it later to the Express object:
Expressapp = newExpress() {{
// Define root greetingget("/", (req, res) -> res.send("Hello World!"));
// Define home routesuse("/home", newExpressRouter(){{
get("/about", (req, res) -> res.send("About page"));
get("/impressum", (req, res) -> res.send("Impressum page"));
get("/sponsors", (req, res) -> res.send("Sponsors page"));
}});
// Define root routesuse("/", newExpressRouter(){{
get("/login", (req, res) -> res.send("Login page"));
get("/register", (req, res) -> res.send("Register page"));
get("/contact", (req, res) -> res.send("Contact page"));
}});
// Start serverlisten();
}};Over the express object you can create handler for all request-methods and contexts. Some examples:
app.get("/home", (req, res) -> {
// Will match every request which uses the 'GET' method and matches the '/home' path
});
app.post("/login", (req, res) -> {
// Will match every request which uses the 'POST' method and matches the /login' path
});Sometimes you want to create dynamic URL where some parts of the URL's are not static.
With the : operator you can create variables in the URL which will be saved later in a HashMap.
Example request: GET/posts/john/all:
app.get("/posts/:user/:description", (req, res) -> {
Stringuser = req.getParam("user"); // Contains 'john'Stringdescription = req.getParam("description"); // Contains 'all'res.send("User: " + user + ", description: " + description); // Send: "User: john, description: all"
});You can also add an event listener when the user called an route which contains an certain parameter.
app.get("/posts/:user/:id", (req, res) -> {
// Code
});For example, if we want to check every id before the associated get post etc. handler will be fired, we can use the app.onParam([PARAM]) function:
app.onParam("id", (req, res) -> {
// Do something with the id parameter, eg. check if it's valid.
});Now, this function will be called every time when an context is requested which contains the id parameter placeholder.
If you make an request which contains querys, you can access the querys over req.getQuery(NAME).
Example request: GET/posts?page=12&from=john:
app.get("/posts", (req, res) -> {
Stringpage = req.getQuery("page"); // Contains '12'Stringfrom = req.getQuery("from"); // Contains 'John'res.send("Page: " + page + ", from: " + from); // Send: "Page: 12, from: John"
});With req.getCookie(NAME) you can get an cookie by his name, and with res.setCookie(NAME, VALUE) you can easily set an cookie.
Example request: GET/setcookie:
app.get("/setcookie", (req, res) -> {
Cookiecookie = newCookie("username", "john");
res.setCookie(cookie);
res.send("Cookie has been set!");
});Example request: GET/showcookie:
app.get("/showcookie", (req, res) -> {
Cookiecookie = req.getCookie("username");
Stringusername = cookie.getValue();
res.send("The username is: " + username); // Prints "The username is: john"
});Over req.getFormQuery(NAME) you receive the values from the input elements of an HTML-Form.
Example HTML-Form:
<formaction="http://localhost/register" method="post"><inputdescription="text" name="email" placeholder="Your E-Mail"><inputdescription="text" name="username" placeholder="Your username"><inputdescription="submit"></form>Attention: Currently, File-inputs don't work, if there is an File-input the data won't get parsed!
Now description, for the example below, john in username and john@gmail.com in the email field.
Java code to handle the post request and access the form elements:
app.post("/register", (req, res) -> {
Stringemail = req.getFormQuery("email");
Stringusername = req.getFormQuery("username");
// Process data// Prints "E-Mail: john@gmail.com, Username: john"res.send("E-Mail: " + email + ", Username: " + username);
});This class represents the entire HTTP-Server, the available methods are:
app.get(Stringcontext, HttpRequesthandler); // Add an GET request handlerapp.post(Stringcontext, HttpRequesthandler); // Add an POST request handlerapp.patch(Stringcontext, HttpRequesthandler); // Add an PATCH request handlerapp.put(Stringcontext, HttpRequesthandler); // Add an PUT request handlerapp.delete(Stringcontext, HttpRequesthandler); // Add an DELETE request handlerapp.all(HttpRequesthandler); // Add an handler for all methods and contextsapp.all(Stringcontext, HttpRequesthandler); // Add an handler for all methods but for an specific contextapp.all(Stringcontext, Stringmethod, HttpRequesthandler); // Add an handler for an specific method and contextapp.use(Stringcontext, Stringmethod, HttpRequesthandler); // Add an middleware for an specific method and contextapp.use(HttpRequesthandler); // Add an middleware for all methods but for an specific contextapp.use(Stringcontext, HttpRequesthandler); // Add an middleware for all methods and contextsapp.use(Stringcontext, ExpressRouterrouter); // Add an router for an specific root contextapp.use(ExpressRouterrouter); // Add an router for the root context (/)app.onParam(Stringname, HttpRequesthandler); // Add an listener for an specific url parameterapp.getParameterListener(); // Returns all parameterlistenerapp.get(Stringkey); // Get an environment variableapp.set(Stringkey, Stringval); // Set an environment variableapp.isSecure(); // Check if the server uses HTTPSapp.setExecutor(Executorexecutor); // Set an executor service for the requestapp.listen(); // Start the async server on port 80app.listen(ExpressListeneronstart); // Start the async server on port 80, call the listener after startingapp.listen(intport); // Start the async server on an specific portapp.listen(ExpressListeneronstart, intport); // Start the async server on an specific port call the listener after startingapp.stop(); // Stop the server and all middleware workerOver the response object, you have serveral possibility like setting cookies, send an file and more. Below is an short explanation what methods exists:
(We assume that res is the Response object)
res.getContentType(); // Returns the current content typeres.setContentType(MediaTypetype); // Set the content type with enum helpres.setContentType(Stringtype); // Set the content typeres.isClosed(); // Check if the response is already closedres.getHeader(Stringkey); // Get the value from an header field via keyres.setHeader(Stringkey, Stringval); // Add an specific response headerres.sendAttachment(Pathfile) // Sends a file as attachmentres.send(Stringstr); // Send a string as responseres.send(Pathpath); // Send a file as responseres.send(byte[] bytes) // Send bytes as responseres.send(); // Send empty responseres.redirect(Stringlocation); // Redirect the request to another urlres.setCookie(Cookiecookie); // Add an cookie to the responseres.sendStatus(Statusstatus); // Set the response status and send an empty responseres.getStatus(); // Returns the current statusres.setStatus(Statusstatus); // Set the repose statusres.streamFrom(longcontentLength, InputStreamis, MediaTypemediaType) // Send a inputstream with known length and typeThe response object calls are comments because you can only call the .send(xy) once each request!
Over the Request Object you have access to serveral request stuff (We assume that req is the Request object):
req.getAddress(); // Returns the INET-Adress from the clientreq.getMethod(); // Returns the request methodreq.getPath(); // Returns the request pathreq.getContext(); // Returns the corresponding contextreq.getQuery(Stringname); // Returns the query value by namereq.getHost(); // Returns the request hostreq.getContentLength(); // Returns the content lengthreq.getContentType(); // Returns the content typereq.getMiddlewareContent(Stringname); // Returns the content from an middleware by namereq.getFormQuerys(); // Returns all form querysreq.getParams(); // Returns all paramsreq.getQuerys(); // Returns all querysreq.getFormQuery(Stringname); // Returns the form value by namereq.getHeader(Stringkey); // Returns the value from an header field by namereq.getParam(Stringkey); // Returns the url parameter by namereq.getApp(); // Returns the related express appreq.getCookie(Stringname); // Returns an cookie by his namereq.getCookies(); // Returns all cookiesreq.getIp(); // Returns the client IP-Addressreq.getUserAgent(); // Returns the client user agentreq.getURI(); // Returns the request URIreq.isFresh(); // Returns true if the connection is fresh, false otherwise (see code inline-doc)req.isStale(); // Returns the opposite of req.fresh;req.isSecure(); // Returns true when the connection is over HTTPS, false otherwisereq.isXHR(); // Returns true if the 'X-Requested-With' header field is 'XMLHttpRequest'req.getProtocol(); // Returns the connection protocolreq.getAuthorization(); // Returns the request authorizationreq.hasAuthorization(); // Check if the request has an authorizationreq.pipe(OutputStreamstream, intbuffersize); // Pipe the request body to an outputstreamreq.pipe(Pathpath, intbuffersize); // Pipe the request body to an filereq.getBody(); // Returns the request inputstreamMiddleware are one of the most important features of JavaExpress, with middleware you can handle a request before it reaches any other request handler. To create an own middleware you have serveral interfaces:
HttpRequest- Is required to handle an request.ExpressFilter- Is required to put data on the request listener.ExpressFilterTask- Can be used for middleware which needs an background thread.
Middlewares work, for you, exact same as request handler. For example an middleware for all request-methods and contexts:
// Global context, matches every request.app.use((req, res) -> {
// Handle data
});You can also filter by request-methods and contexts:
// Global context, you can also pass an context if you wantapp.use("/home", "POST", (req, res) -> {
// Handle request by context '/home' and method 'POST'
});In addition to that yo can use * which stands for every context or request-method:
// Global context, you can also pass an context if you wantapp.use("/home", "*", (req, res) -> {
// Handle request which matches the context '/home' and all methods.
});Now we take a look how we can create own middlewares. Here we create an simple PortParser which parse / extract the port-number for us. We only used HttpRequest and ExpressFilter because we don't need any background thread.
publicclassPortMiddlewareimplementsHttpRequest, ExpressFilter {
/** * From interface HttpRequest, to handle the request. */@Overridepublicvoidhandle(Requestreq, Responseres) {
// Get the portintport = req.getURI().getPort();
// Add the port to the request middleware mapreq.addMiddlewareContent(this, port);
/** * After that you can use this middleware by call: * app.use(new PortMiddleware()); * * Than you can get the port with: * int port = (Integer) app.getMiddlewareContent("PortParser"); */
}
/** * Defines the middleware. * * @return The middleware name. */@OverridepublicStringgetName() {
return"PortParser";
}
}Now we can, as we learned above, include it with:
// Global context, you can also pass an context if you wantapp.use(newPortMiddleware());And use it:
app.get("/port-test", (req, res) -> {
// Get the content from the PortParser which we create aboveintport = (Integer) req.getMiddlewareContent("PortParser");
// Return it to the client:res.send("Port: " + port);
});There are already some basic middlewares included, you can access these via static methods provided from Middleware.
To realize a cors api yu can use the cors middleware.
app.use(Middleware.cors());You can use CorsOptions to specify origin, methods and more:
CorsOptionscorsOptions = newCorsOptions();
corsOptions.setOrigin("https://mypage.com");
corsOptions.setAllowCredentials(true);
corsOptions.setHeaders(newString[]{"GET", "POST"});
corsOptions.setFilter(req -> // Custom validation if cors should be applied);app.use(Middleware.cors());If you want to allocate some files, like librarys, css, images etc. you can use the static middleware. But you can also provide other files like mp4 etc.
Example:
app.use(Middleware.statics("examplepath\\myfiles"));Now you can access every files in the test_statics over the root adress \. I'ts also possible to set an configuration for the FileProvider:
FileProviderOptionsoptions = newFileProviderOptions();
options.setExtensions("html", "css", "js"); // By default, all are allowed./* * Activate the fallbacksearch. * E.g. if an request to <code>/js/code.js</code> was made but the * requested ressource cannot be found. It will be looked for an file called <code>code</code> * and return it. * * Default is false */options.setFallBackSearching(true);
options.setHandler((req, res) -> {...}); // Can be used to handle the request before the file will be returned.options.setLastModified(true); // Send the Last-Modified header, by default true.options.setMaxAge(10000); // Send the Cache-Control header, by default 0.options.setDotFiles(DotFiles.DENY); // Deny access to dot-files. Default is IGNORE.app.use(Middleware.statics("examplepath\\myfiles", newFileProviderOptions())); // Using with StaticOptionsThere is also an simple cookie-session implementation:
// You should use an meaningless cookie name for serveral security reasons, here f3v4.// Also you can specify the maximum age of the cookie from the creation date and the file types wich are actually allowed.app.use(Middleware.cookieSession("f3v4", 9000));To use a session cookie we need to get the data from the middleware which is actually an SessionCookie:
// Cookie session exampleapp.get("/session", (req, res) -> {
/** * CookieSession named his data "Session Cookie" which is * an SessionCookie so we can Cast it. */SessionCookiesessionCookie = (SessionCookie) req.getMiddlewareContent("sessioncookie");
intcount;
Checkifthedataisnull, wewanttoimplementansimplecounterif (sessionCookie.getData() == null) {
// Set the default data to 1 (first request with this session cookie)count = (Integer) sessionCookie.setData(1);
} else {
// Now we know that the cookie has an integer as data property, increase itcount = (Integer) sessionCookie.setData((Integer) sessionCookie.getData() + 1);
}
Sendaninfomessageres.send("You take use of your session cookie " + count + " times.");
});Java-express also supports to save and read global variables over the Express instance.
app.set("my-data", "Hello World");
app.get("my-data"); // Returns "Hello World"// Create instancenewExpress() {{
// Define middleware-route for static siteuse("/", Middleware.statics("my-website-folder/"));
}};// Your filePathdownloadFile = Paths.get("my-big-file");
// Create instancenewExpress() {{
// Create get-route where the file can be downloadedget("/download-me", (req, res) -> res.sendAttachment(downloadFile));
}};newExpress() {{
// Define routeget("/give-me-cookies", (req, res) -> {
// Set an cookie (you can call setCookie how often you want)res.setCookie(newCookie("my-cookie", "Hello World!"));
// Send textres.send("Your cookie has been set!");
});
}};This project is licensed under the MIT License - see the LICENSE file for details.
