Inspired by Flask, Cask allows you to define your web applications endpoints using simple function def
s that you already know and love, annotated with the minimal additional metadata necessary to work as HTTP endpoints.
It turns out that function def
s already provide almost everything you need in a HTTP endpoint:
Response
Cask extends these basics with annotations, providing:
def
with custom logic: logging, authentication, ...While these annotations add a bit of complexity, they allow Cask to avoid needing custom DSLs for defining your HTTP routes, custom action-types, and many other things which you may be used to working with HTTP in Scala.
Unlike most other annotation-based frameworks in Scala or Java, Cask's annotations are not magic markers, but self-contained classes containing all the logic they need to function. This has several benefits:
You can jump to the definition of an annotation and see what it does
It trivial to implement your own annotations as decorators or endpoints.
Stacking multiple annotations on a single function has a well-defined contract and semantics
Overall, Cask annotations behave a lot more like Python decorators than "traditional" Java/Scala annotations: first-class, customizable, inspectable, and self-contained. This allows Cask to have the syntactic convenience of an annotation-based API, without the typical downsides of inflexibility and undiscoverability.
Cask intentionally eskews many things that other, more enterprise-grade frameworks provide:
While these features all are valuable in specific cases, Cask aims for the 99% of code for which simple, boring code is perfectly fine. Cask's endpoints are synchronous by default, do not tie you to any underlying concurrency model, and should "just work" without any advanced knowledge apart from basic Scala and HTTP. Cask's websockets API is intentionally low-level, making it both simple to use and also simple to build on top of if you want to wrap it in your own concurrency-library-of-choice.
Cask is implemented as a thin wrapper around the excellent Undertow HTTP server. If you need more advanced functionality, Cask lets you ask for the exchange:
HttpServerExchange
in your endpoint, override defaultHandler and add your own Undertow handlers next to Cask's and avoid Cask's routing/endpoint system altogether, or override main if you want to change how the server is initialized.
Rather than trying to provide APIs for all conceivable functionality, Cask simply provides what it does best - simple routing for simple endpoints - and leaves the door wide open in case you need to drop down to the lower level Undertow APIs.
Cask aims to re-use much of the excellent code that is already written and being used out in the Scala community, rather than trying to re-invent the wheel. Cask uses the Mill build tool, comes bundled with the uPickle JSON library, and makes it trivial to pull in libraries like Scalatags to render HTML or ScalaSql for database access.
Each of these are stable, well-known, well-documented libraries you may already be familiar with, and Cask simply provides the HTTP/routing layer with the hooks necessary to tie everything together (e.g. into a TodoMVC webapp)
About the Author: Haoyi is a software engineer, an early contributor to Scala.js, and the author of many open-source Scala tools such as Cask, the Ammonite REPL and FastParse.
If you've enjoy using Cask, or enjoyed using Haoyi's other open source libraries, please chip in (or get your Company to chip in!) via Patreon so he can continue his open-source work