Important Notice: Repository History Change on 2023-11-12
Boom is a simple convention-over-configuration library that wraps around Spark to allow simple web applications to be built extremely quickly. Its primary goal is to match my own development style and reduce boilerplate. Hopefully you'll find it useful, too.
import static com.martiansoftware.boom.Boom.*;
Use com.martiansoftware.boom.Boom in place of spark.Spark for additional functionality. Spark is used behind the scenes by Boom. You can still call Spark directly from the same application if you like.
When registering Routes (e.g., Spark's get() and post() methods), you can alternately specify a BoomRoute, which takes no arguments and returns an Object. Spark's Request and Response objects for the current Thread are made available by Boom's request() and response() methods, so your BoomRoute implementations can do this (assuming static method App.doThing()):
get("/thing", App::doThing);
instead of this:
get("/thing", (req,rsp) -> App.doThing(req,rsp));
Routes (and BoomRoutes) can continue return any type of Object for Spark to render to the client. But if you return a BoomResponse then a number of things are taken care of for you automatically.
The BoomResponse() constructor can take a String, InputStream, File, or URL as an argument. In each case you will get what you expect; the InputStream (or String, File, or URL contents, etc.) will be copied to the client. If a File or URL has a file extension, Boom will set the appropriate MIME type as well.
Type helpers and a fluent interface allow a single call to performa multiple tasks like:
private static Object doThing() {
return new BoomResponse("{'thing':'done'}").json();
}
Boom provides some static methods for easier construction and initialization of BoomResponses as well:
private static Object getThing() {
// json-ification is automatic
// mime type set to "application/json"
return json(someObject);
}
private static Object getFile() {
// mime type set to "application/octet-stream"
return binary(myFile);
}
private static Object getXml() {
// mime type set to "text/xml"
return xml(something.getXmlInputStream());
}
private static Object getText() {
// mime type set to "text/plain"
return text("just plain old text here...");
}
If the environment variable or system property BOOM_DEBUG
is "1", then certain behaviors are modified to support development (described here and there below).
Static content is automatically configured to load from the classpath under /static-content. For Maven projects, just put static content files into src/main/resources/static-content
and it's all set up for you. When your jar is bundled and delivered, static content will automatically be packaged and included by Maven.
If running in Debug Mode, then static content is instead automatically configured to load from the filesystem under src/main/resources/static-content
instead of from your classpath. This allows reloading of content from the filesystem during development without restarting your application.
You can use Spark's built-in template functionality (or whatever else you'd like to use), but Boom provides helpers for use with DumbTemplates. Template can be obtained from Boom via template(templateName)
.
Behavior is similar to that for static content: templates are automatically configured to load from the classpath under /templates
. For Maven projects, just put them into src/main/resources/templates
and it's all set up for you. When your jar is bundled and delivered, templates will be automatically packaged and included by Maven.
If running in Debug Mode, then templates are instead automatically configured to load from the filesystem under src/main/resources/templates
instead of from your classpath. This allows reloading of templates from the filesystem during development without restarting your application.
Boom provides a helper method for loading ResourceBundles. If you store your bundles in the classpath under /bundles
, then Boom's r(bundlename)
will retrieve it for you. For Maven projects, put them into src/main/resources/bundles
.
A future update will store end user locale information in the session and use that to load the appropriate bundle automatically. Of course, you'll be able to manually set the user's locale as well.
To customize the html returned on exceptions or halts, use DumbTemplates in your classpath under /templates/boom/status/CODE.html
, where CODE is the status code for which you are customizing the output. For example, for a custom Error 503 page, use /templates/boom/status/503.html
. If no template is found, /templates/boom/status/default.html
is then tried, so you can provide a general override if you like. Boom will place "status" and "body" values in the template context.
Boom provides form-based authentication (you're using SSL/TLS, right?) Setting it up is easy but it does require a few steps.
- Implement a
UserLookup
. This is a simple interface incom.martiansoftware.boom.auth
that looks up a user by name via itsbyName(String)
method, returning anOptional<User>
. Implementations should be lenient in interpreting the username (e.g. by accepting mixed case, leading and trailing whitespace, etc.) - Implement a
User
that yourUserLookup
can provide.User
s must provide acanonicalName()
method and ahasPermission(Object)
method. - Create a
FormLoginFilter
. This is a class incom.martiansoftware.boom.auth
that filters requests and presents a login page when required. The default login page templates are inboom-default-templates.FormLoginFilter
and can be customized by placing your ownFormLoginFilter/login.html
andFormLoginFilter/loggedout.html
templates in your own template directory as described above. Take a look at the default login.html form to see the appropriate query parameters and POST destination.FormLoginFilter
's constructor takes a single argument: theAuthenticator
you created in the previous step. - Exempt any paths that DO NOT require authentication in the
FormLoginFilter
via its exempt() method. This method returns the modifiedFormLoginFilter
so it may be chained as follows:
myFormLoginFilter.exempt("/favicon.ico").exempt("/styles.css").exempt("/images/logo.png");
- Tell Boom to use your
FormLoginFilter
viaBoom.login()
.
Boom will automatically exempt the /login
and /logout
paths used by FormLoginFilter
.
A bunch of things remain planned:
- Automatic CSRF protection (already done in another project, needs to be extracted and cleaned up)
- i18n
- maybe provide separate jars bundling existing static content (e.g. jquery, font-awesome, etc.) or use WebJars
- Maven project archetype or other project setup tool
- Debug-mode use of external tools like request.bin or other http test endpoints