Bare-Metal REST With a Few Lines of Code
Let's skip using heavy-weight frameworks doing magic in the background. Let's follow the classic bare-metal approach where we're in full control of the app lifecycle.
Join the DZone community and get the full member experience.
Join For FreeIn this article, find out about an alternative approach for implementing a tiny and slim RESTful service or a tiny and slim REST client with a little help from Java's lambda expressions. We skip using heavy-weight frameworks doing magic in the background. Instead, we will follow the classic bare-metal approach where you stay in full control of your application’s lifecycle.
According to Techopia:
"Bare-Metal programming is a term for programming that operates without various layers of abstraction or, as some experts describe it, without an operating system supporting it."
In this context, I use the term bare-metal for programming that operates without various layers of abstraction regarding the Java ecosystem.
A while ago, I was thinking about what became of good old imperative object-oriented Java programming.
Then came generics, keeping your code comprehensible and more reliable, which is a good thing. Then came lambda expressions, and with them, more functional programming, still keeping your code comprehensible, still being a good thing. Then came the heavy-weight frameworks, doing all kinds of magic in the background: scanning your classpath, introspecting your bytecode, making decisions not easily traceable by you, the programmer, taking over your application’s lifecycle, placing you, the programmer, under disability.
Do we really need full-blown lifecycle management and web container support in a microservices and IoT world?
Motivation
What I actually want to do when programming is to keep control:
I want to instantiate some class with which I can do REST requests. I want to instantiate some class with which I can do RESTful services. I don’t want to buy classpath
scanning or bytecode introspection only for doing REST. I want to do bare-metal programming instead of programming in a steel-boned corset of some application server or heavy-weight framework …
The refcodes-rest
artifact is just one piece of the puzzle for doing so. For example, you can open up as many HTTP/HTTPS ports for as many different lambda in a single serverless RESTful service as you wish.
You may skip the below bare-metal section if you want to dive directly into the refcodes-rest
programming.
Bare-Metal
In comparison to the heavy-weight frameworks, bare-metal (and therewith the refcodes-rest
artifact) follows an opposite approach: Give the programmer back the control.
Bare-metal programming is the kinda programming where you decide on how your application is constructed, where you control the lifecycle and where you create a damn simple listener for processing a resource’s REST request instead of spreading tons of framework specific annotations over your code, interpreted magically by a framework at runtime.
Let's get an impression on the overhead your applications are carrying around. Using Spring Boot, just to get a RESTful service up-and-running, your archive including all required libraries get about 13 MB of size. Moreover, Spring Boot takes over full control of your application’s lifecycle. No bare-metal anymore.
In comparison, the bare-metal approach using the refcodes-rest
artifact would fit on three 3.5 inch floppy disks and still keep you in full control of your application’s lifecycle (even including a full-blown bare-metal refcodes-console
command line args parser).
Note: a + represents 1 MB in the table below.
Stack | Size (MB) | Bare-Metal |
---|---|---|
Spring Boot | +++++++++++++ | No, placing the programmer under disability |
refcodes-rest |
+++ | Yes, programmer keeps full control |
I admit that the above is a very one-sided, selective, and exaggerated comparison of two very different things. The point I am investigating here is the question of whether it would be more sufficient to use bare-metal straight-forward imperative programming paradigms instead of heavy-weight frameworks because our services’ complexity is continuously shrinking. I implemented a bare-metal API for doing client side REST requests and for implementing tiny RESTful servers.
Getting Started
To get up and running, include the following dependency (without the three dots “…”) in your pom.xml
:
<dependencies>
...
<dependency>
<artifactId>refcodes-rest</artifactId>
<groupId>org.refcodes</groupId>
<version>1.1.2</version>
</dependency>
...
</dependencies>
For tweaking your configuration such as binding to SLF4J, see the refcodes-rest
blog post.
The Restful Server
The TinyRestfulServer
demo application uses syntactic sugar for setting up a RESTful server including command line arguments parsing. Basically, it requires these three steps to get your RESTful server up and running:
- Instantiate the RESTful server.
- Register your lambda expressions.
- Start the RESTful server.
...
public static void main( String[] args ) {
// STEP 1: We instantiate our HttpRestServer:
HttpRestServer theRestServer = new HttpRestServerImpl();
// STEP 2: We register our lambda expression:
theRestServer.onGet( "/say/${name}=*", ( aRequest, aResponse ) -> {
String name = aRequest.getWildcardReplacement( "name" );
aResponse.getHeaderFields().withContentType( MediaType.APPLICATION_JSON ).withAddCookie( "greeting", "Hello " + name + "!" );
return "Hello " + name + "!" ;
} ).open();
// STEP 3: We open the HttpRestServer instance on port 8080:
theRestServer.open( 8080 );
}
...
The above example registers to the imaginary resource “/say
” and provides you with the addressed element (“name
”). You may produce a response including cookies and required Header-Fields via the provided lambda expression.
Under the Hood
The diagram BELOW illustrates the interaction between a client A, the server B, and the business part C:
- A: The client such as a browser or the
HttpRestClient
issuing anHTTP-Request
. - B: The
HttpRestServer
receiving theHTTP-Request
. - X: Your
RestEndpoint
processing theHTTP-Request
and producing a response.
- The client issues an HTTP-Request with a given
HttpMethod
(GET, POST, PUT or DELETE). - The
HttpRestServer
analyzes the request and dispatches it to the accordingRestEndpoint
. - Its
HttpMethod
must match and theLocator-Pattern
must match theLocator
. - The lambda of the matching
RestEndpoint
is invoked and produces a response - The
HttpRestServer
marshals the response and sends it back to the client - The client receives the HTTP-Response as produced by your lambda.
The REST Client
Basically, it requires these three steps for firing a REST request from within your client:
- Instantiate the REST client
- Register your lambda expression for the response
- Fire the client’s REST request
...
public static void main( String[] args ) {
// STEP 1: We instantiate our HttpRestClient:
HttpRestClient theRestClient = new HttpRestClientImpl();
// STEP 2: We register our lambda expression:
theRestClient.doRequest( HttpMethod.POST, "http://mydomain:8080/say/nolan", ( aResponse ) -> {
String theResponse = aResponse.getResponse( String.class );
} ).withRequest( ... ).open();
// STEP 3: We opened the caller so it fires the request to port 8080 of domain "mydomain"
}
...
The above example issues a POST request to some imaginary “/say
” resource, addressing the element “nolan
” and with some request body (any Object
which can be marshaled with the according Content-Type
) and processes the response asynchronously via the provided lambda expression.
Under the Hood
The diagram illustrates the interaction between the business part A, the client B, and a server C:
- A: Your
RestCaller
producing theHTTP-Request
and processing the response. - B: The
HttpRestClient
sending theHTTP-Request
. - C: The server such as the
HttpRestServer
receiving anHTTP-Request
.
- The HTTP-Request of your
RestCaller
is processed by theHttpRestClient
. - The
HttpRestClient
marshals the request and sends it to the server. - The server receives the HTTP-Request as produced by your
RestCaller
. - An
HTTP-Response
is produced by the server and passed back to theHttpRestClient
. - The
HttpRestClient
invokes the lambda of theRestCaller
with the response. - The lambda of the
RestCaller
is invoked and processes the response.
Published at DZone with permission of Siegfried Steiner. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments