Inspired by Flask, Cask allows you to define your web applications endpoints using simple function
defs that you already know and love, annotated with the minimal additional metadata necessary to work as HTTP endpoints.
It turns out that function
defs already provide almost everything you need in a HTTP endpoint:
Cask extends these basics with annotations, providing:
defwith 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
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
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 Quill 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)
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