The Rebirth of Athena
Tags: crystal, framework, symfony, sinatra
Published: 2020-02-11 19:46:35

---
title: The Rebirth of Athena
published: true
description: A look at Athena's past, present, and future
tags: #crystal, #framework, #symfony, #sinatra
---

# Rebirth

The past year has been quite the journey for [Athena](https://github.com/athena-framework/athena).  It felt like not too long ago when I released version `0.1.0`, however now, after a lot of thinking, multiple iterations, and 7 minor versions later, I'm proud to announce the release of `0.8.0`, or what I like to call `Rebirth`.  This release brings about changes to nearly every part of Athena, both user facing and internally, as well as changes to the [vision](https://github.com/athena-framework/athena/issues/34) and [organizational](https://github.com/athena-framework) future of the Athena Framework itself.

Since its been a while since my last post, I thought I would take this opportunity to highlight some of the changes introduced in this latest version as well as give an update on the roadmap/vision for the framework as a whole.  This blog post isn't intended to be a tutorial on how to use these features, I will however provide plenty of links out to examples or documentation either in the [Blog Demo App](https://github.com/Blacksmoke16/athena-blog-tutorial)/[Blog Post](https://dev.to/blacksmoke16/creating-a-json-api-with-athena--granite-510i) or the [API docs](https://athena-framework.github.io/athena/Athena/Routing.html).  Also, feel free to join me in the Athena [Gitter](https://gitter.im/athena-frameworkcr/community) channel.

## Organizational

As part of this latest release, I took the time to make some organizational changes; this resulted in the creation of the [athena-framework](https://github.com/athena-framework) Github organization, which will be the home to all of the frameworks components.  Related to this, I  moved some of the components that were included in `athena` core into the organization; namely [dependency-injection](https://github.com/athena-framework/dependency-injection) and [config](https://github.com/athena-framework/config).  The main benefit of this is it allows other shards, outside of the Athena Framework to use each component independently from one another.  The longer term goal is creating a common set of useful components that can be used by others, versus everyone creating a slightly different version of the same thing.

`0.8.0` also removed the direct dependencies on [crylog](https://github.com/Blacksmoke16/crylog) and [CrSerializer](https://github.com/Blacksmoke16/CrSerializer).  These, along with [assert](https://github.com/Blacksmoke16/assert) are going to be reworked to be more DI friendly, as well as work out some issues with their implementations I found along the way.  They will then be moved into the `athena-framework` organization.  The plan for how these will be reintegrated into `Athena ` will be discussed in the [DependencyInjection](#dependency-injection-di) section.

Athena makes use of namespaces to group common types together, both for organizational and documentation purposes.  This practice however can lead to really long names, such as `Athena::Routing::Exceptions::NotFoundException.new ""` as you might have used once or twice.  Unfortunately without an import system, like ES6 for example, there isn't really a way around this.  In order to help alleviate this issue in the mean time, I created various three letter acronyms that point to each component's namespace.  For example, [ART](https://athena-framework.github.io/athena/ART.html)  for `Athena::Routing`, or [AED](https://athena-framework.github.io/athena/AED.html) for `Athena::EventDispatcher`.  Using these aliases in `0.8.0` the previous example would now be `ART::Exceptions::NotFound.new ""`.  

## Event Dispatcher

The most impactful change was the implementation of a [Mediator and Observer pattern event library](https://github.com/athena-framework/event-dispatcher) to handle the core logic of handling a request, as well as a replacement for `HTTP::Handler` style middleware.  Athena internally now operates by emitting various [events](https://athena-framework.github.io/athena/Athena/Routing/Events.html) that can be listened on in order to handle a request.  Athena defines various [listeners](https://athena-framework.github.io/athena/Athena/Routing/Listeners.html) itself as well; including for routing, CORS, exceptions, and a view layer, which I will get to soon.  Each event contains information related to the event, for example the `Request` event contains the current request, while the `Exception` event contains the current request and the exception that was raised.

The main advantage of this approach is it is much easier to add middleware to the framework since an array of `HTTP::Handler` do not have to be supplied up front.  The listener approach is also much more flexible since the order of execution can be more easily controlled, versus being based on the order of the handler array.  Listeners could be defined in external shards and just by requiring it, the listener(s) would automatically be registered.

The other big advantage is listeners support DI, so other dependencies can be injected into the listener as needed.  An example of this could be a [security listener](https://github.com/Blacksmoke16/athena-blog-tutorial/blob/master/src/listeners/security_listener.cr) on the `Request` event in order to authenticate a request; lookup the corresponding user, and set it within a service that exposes that user to the rest of the application.  Another example could be listening on exceptions in order to log information about them for analytics or monitoring.  

```crystal
@[ADI::Register("@logger", tags: ["athena.event_dispatcher.listener"])]
# Define a listener to handle authenticating requests.
# Also register it as a service and give it the proper tag for it to be automatically registered.
struct MonitoringListener
  # Define the interface to implement the required methods
  include AED::EventListenerInterface

  # Define this type as a service for DI to pick up.
  include ADI::Service

  # Specify that we want to listen on the `Exception` event.
  # The value of the has represents this listener's priority;
  # the higher the value the sooner it gets executed.
  def self.subscribed_events : AED::SubscribedEvents
    AED::SubscribedEvents{
      ART::Events::Exception => 0,
    }
  end

  # Define our initializer for DI to inject a logger instance.
  def initialize(@logger : LoggerInterface); end

  # Define a `#call` method scoped to the `Exception` event.
  def call(event : ART::Events::Exception, _dispatcher : AED::EventDispatcherInterface) : Nil
     # Log the exception message
     @logger.error event.exception.message
        
    # Do whatever else you want to do with the event, including emitting other events
  end
end
```

Custom events can also be defined that can be emitted from user code, either from another listener, controller action, etc.  The `EventDispatcher` component can also be used independently outside of Athena. 

## Dependency Injection (DI)

The change to a listener based approach originated due to another flaw in the `HTTP::Handler` approach; they do not play nicely with DI.  The main issue is that they are instantiated once when you create the `HTTP::Server`, outside of the request life-cycle, thus the service container is not available to inject dependencies, nor can the middleware exist as a service itself.

This fact, along with how common middleware is, made me want to rethink the overall design of Athena to be more DI friendly.  As mentioned in the [Interfaces & DI](https://github.com/athena-framework/athena/issues/34#interfaces-and-di) section in the vision issue, the ultimate goal is to make Athena solely depend on interfaces versus concrete types.  This not only allows for a better DI implementation, but also make custom implementations, and testing easier.

The plan for the serializer and logger components is that they are optional; but if installed and required, have an `ext`, or `plugin`, or something, file that would better integrate it into the rest of the framework.  An example of this could be defining some types from that component as services, or defining a basic implementation of an interface for use within Athena.  For example:

```crystal
# ext/logger.cr
@[ADI::Register(name: "logger")]
# Define a basic implementation of a logger service for services to inject
struct Logger
  # Be sure it adheres to the interface.  This also would allow
  # external/third-party code to define their own implementation
  # of the logger service to use
  include LoggerInterface

  ...
end

# some_controller.cr
require "athena/ext/logger"

class SomeController < ART::Controller
  include ADI::Injectable
  
  # The logger could be injected into anything logging is needed.
  # Each request would have its own logger instance
  def initialize(@logger : LoggerInterface); end
  
  @[ART::Get("some/path")]
  def some_path : String
    @logger.info "Some message"
    ...
  end
end
```

Internally, Athena would utilize [optional services](https://athena-framework.github.io/dependency-injection/Athena/DependencyInjection/Register.html#optional-dependencies) to manage this.  I.e. by default no logging, but if a `logger` service is registered and available, use that; such as for debug information on each request, or logging exceptions etc.

### ErrorRendererInterface

The `ErrorRendererInterface` is a perfect example of how DI fits into the framework.  The [default](https://athena-framework.github.io/athena/Athena/Routing/ErrorRenderer.html) error renderer will JSON serialize the exception and return that string to the client.  However, this behavior is customizable by [redefining](https://athena-framework.github.io/dependency-injection/Athena/DependencyInjection/Register.html#redefining-services) the `error_renderer` service; if for example you wish to return an HTML error page or something.

## View Layer

In previous versions of Athena, the response format was not very customizable.  The implementation was tied to some type that defines a `render` class method on it.  Once again this does not fit into the DI oriented framework I so desire, so I had to rethink the implementation to better handle that as well as improve the overall flexibility of the framework.

The solution to this is two fold, the [ART::Response](https://athena-framework.github.io/athena/Athena/Routing/Response.html) type and the [view](https://athena-framework.github.io/athena/Athena/Routing/Events/View.html) event.

### ART::Response

The concept behind the `ART::Response` type is that it represents a "pending" response to the client.  It can be mutated, body rewritten etc, all without affecting the actual `HTTP::Server::Response`.  The idea behind it is that a controller action can either return an `ART::Response` or not; the behavior of the framework changes slightly if the return value is an `ART::Response`.

If a controller action returns an `ART::Response`, or a subclass of it like [ART::RedirectResponse](https://athena-framework.github.io/athena/Athena/Routing/RedirectResponse.html), then that object is used directly as the response to the client; body, status, and headers are simply copied over to the actual `HTTP::Server::Response`.  This allows an action to return arbitrary data easily to fulfill simple use cases. 

```crystal
class TestController < ART::Controller
  @[ART::Get("/css")]
  def css : ART::Response
    # A controller action returning CSS.
    ART::Response.new ".some_class { color: blue; }", headers: HTTP::Headers{"content-type" => MIME.from_extension(".css")}
  end
end
```

Another thing that came from this is the [render](https://athena-framework.github.io/athena/Athena/Routing/Controller.html#render(template)-macro) macro; it provides a simple way to render `ECR` templates.  The variables used in the template can come directly from the action's arguments, such as the example in the API docs.  This feature combined with [ParamConverterInterface](https://athena-framework.github.io/athena/Athena/Routing/ParamConverterInterface.html) can make for a very easy way to render a user's profile for example:

```crystal
@[ART::Get("/user/:id/profile")]
@[ART::ParamConverter("user", converter: DBConverter(User))]
def user_profile(user : User) : ART::Response
  # Render the user profile for the user with the provided ID.
  # The template has access to the full User object.
  render "user_profile.ecr"
end
```

### ART::Events::View

The second part of the view layer is the [view](https://athena-framework.github.io/athena/Athena/Routing/Events/View.html) event, and the corresponding default [listener](https://athena-framework.github.io/athena/Athena/Routing/Listeners/View.html).  When a controller action's return value is _NOT_ an `ART::Response`, the view event is emitted.  The job of the listeners listening on the event is to convert the resulting value into an `ART::Response`.  The default listener does this by JSON serializing the value, by default using the standard library's `#to_json` method, or in the future, optionally by the `serializer` component if it is installed

In the future, a format negotiation algorithm will be implemented to call the correct renderer based on the request's `Accept` headers.  For now, if you wish to define a global custom format for your routes, you have a few options.  

1. Define a custom `view` listener that runs before the default one (future listeners will not run once [#response=](https://athena-framework.github.io/athena/Athena/Routing/Events/SettableResponse.html#response=(response:ART::Response):Nil-instance-method) is called)
2. Subclass `ART::Response` to encapsulate your logic
3. Define a helper method/macro on `ART::Controller` to encapsulate your logic

Overall these changes make Athena a whole lot more flexible, making it viable to render HTML, or anything else that is required.

## Routing

While not much changed in the routing aspect of Athena, I do want to point out some of the minor changes/additions that did occur.

### QueryParams

In previous versions, query parameters were included directly within the HTTP method annotation as a `NamedTuple`.  In `0.8.0`, [QueryParams](https://athena-framework.github.io/athena/Athena/Routing/QueryParam.html) are now defined by their own dedicated annotation.  They still support constraints, and param converters.

```crystal
@[ART::Get("/example")]
@[ART::QueryParam("value")] # Is typed as a string due to `name : String`
def get_user(name : String) : Nil
end
```

### Macro DSL

One of the draws of [Sinatra](http://sinatrarb.com/), and by extension, [Kemal](https://kemalcr.com/) is the super simple syntax.

```crystal
get "/index"
  "INDEX"
end
```

One of the downsides of Athena that I've heard is its verbosity.  To help with this, I created a similar [macro DSL](https://athena-framework.github.io/athena/Athena/Routing/Controller.html#get(path,*args,**named_args,&)-macro) that simply abstracts the creation of a method and addition of the annotation.

```crystal
class ExampleController < ART::Controller
  # Super simple right?
  get "index" do
    "INDEX"
  end
    
  # It also works with arguments, and other annotations like ParamConverters/QueryParams
  @[ART::QueryParam("value3")]
  get "values/:value1/:value2", value1 : Int32, value2 : Float64, value3 : Int8 do
    "Value1: #{value1} - Value2: #{value2} - Value3: #{value3}"
  end
end
```

It can still get pretty verbose if you have many path arguments, with a non `String` return type, and some route constraints, but this and the three letter acronym aliases will help reduce the learning curve, and make life a little bit easier.

### Access Raw `HTTP::Request`

Before there was not really a way to access the current request object outside of the [RequestStore](https://athena-framework.github.io/athena/Athena/Routing/RequestStore.html), and related, not really an easy way to access the raw response body of said request.  In addition, the action argument's name for `POST` requests had to be `body`.  This was far from ideal and has been improved greatly in `0.8.0`.  The raw `HTTP::Request` and by extension, its body `IO`, can now be accessed by simply typing an action argument to `HTTP::Request`.  Athena will see that and provide the raw object to that action.


```crystal
@[ART::Post(path: "/foo")]
# The name of the argument can be anything as long as its type is `HTTP::Request`.
def post_body(request : HTTP::Request) : String
  request.body.try &.gets_to_end
end
```

## The Future

The overall roadmap for Athena is outlined in the [vision](https://github.com/athena-framework/athena/issues/34) issue.  For the short term I will continue with fixing any issues, and improving the documentation as needed.  I will also continue working on reworking and moving the remaining components into the Github organization.

The medium to long term includes the creation of additional components, such as resurrecting the `CLI` component, as well as introducing a more structured framework to handle authentication and access control of a given route.

As usual, any issues/comments/questions, feel free to drop a comment on this article, or come join me in the Athena [Gitter](https://gitter.im/athena-frameworkcr/community) channel.