# Athena 0.16.0

**URL:** https://forum.crystal-lang.org/t/athena-0-16-0/4251
**Category:** News
**Created:** [January 11, 2022, 11:24pm UTC](https://forum.crystal-lang.org/t/athena-0-16-0/4251 "2022-01-11T23:24:00Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)
#### Post date: [January 11, 2022, 11:24pm UTC](https://forum.crystal-lang.org/t/athena-0-16-0/4251/1 "2022-01-11T23:24:00Z")

</div>

# Athena Framework 0.16.0

This [release](https://github.com/athena-framework/framework/releases/tag/v0.16.0) focused on integrating the new [Routing](https://athenaframework.org/Routing/) component into the framework as well as the introduction of the Athena monorepo.

## Routing Component

[Amber Router](https://github.com/amberframework/amber-router) has served the framework well for the past few years. However, as alluded to in the last release, it was time for an upgrade. I’m happy to announce the [Athena::Routing](https://athenaframework.org/Routing/) component is now finished and integrated into Athena Framework!

Just like all the other components, it can also be used outside of the ecosystem, such as other frameworks, to handle your routing needs. It has quite a few features, and none of the limitations of other Crystal routers:

- Is entirely regex based, allows using regex to define [validations](https://athenaframework.org/Routing/Route/#Athena::Routing::Route--parameter-validation) in order to determine if a given route should match
  - Also supports route priorities and sub-domain matching

- Allows multiple routes with placeholders in the same location thanks to the previous bullet
- Built in support for default values
- Provides annotations that can be used for custom implementations

A regex router you say? That can’t be fast! Thanks to PCRE2’s JIT compilation using the fast-path API, it [sure is](https://gist.github.com/Blacksmoke16/bb3405ef1c224c4f60e4edf0fe2235d4#file-results-txt). The main bottleneck is `URI.decode`. Without that, the results are [even better](https://gist.github.com/Blacksmoke16/bb3405ef1c224c4f60e4edf0fe2235d4#file-results-no-decoding-txt), otherwise is still faster than the other routers in every case except two.

Given routing is a core part of a web framework, this change does come with a few breaking changes. See the changelog for the full list.

### Annotations

- `@[ATHA::Prefix(prefix: "/foo")]` =\> `@[ARTA::Route(path: "/foo")]`
  - Prefixes no longer check parent types. Define a single `ARTA::Route` with the prefix on each controller

- `ATHA::*` routing annotations have been replaced with `ARTA::*` routing annotations

### Trailing slashes are now taken into consideration

`/foo` is a different route when compared to `/foo/`. Be sure to be consistent and follow a common pattern throughout your application.

### Route Parameter Syntax

Route parameters are now defined by wrapping the name within `{}`, such as `/user/{id}`. The primary benefit of this is allowing parameters within other segments, such as `/foo{slug}bar` which would match everything between `foo` and `bar`. It also allows the format of the request path to be captured/restricted. E.g. `/user/{id}.{_format?json}`, which would default to `json` if not provided (`/user/10`) or allow a custom format (`/user/10.xml`). The routing component has a few [special parameters](https://athenaframework.org/Routing/Route/#Athena::Routing::Route--special-parameters), such as `_format`, which will set the format of the request to the matched format if used. This can be especially useful for Athena’s [content negotiation](https://athenaframework.org/components/negotiation/) feature.

## Athena Monorepo

As mentioned in [How I migrated Athena to a Monorepo...and you can too](https://forum.crystal-lang.org/t/how-i-migrated-athena-to-a-monorepo-and-you-can-too/4154), I have migrated Athena to a monorepo such that all of the components can be more easily maintained within a single repository. Given this is the first release after this change you will need to update the repository within `shard.yml` in order to install the update. Athena Framework should now be installed as:

```yaml
dependencies:
  athena:
    github: athena-framework/framework
    version: ~> 0.16.0

```

The only difference being `athena-framework/athena` =\> `athena-framework/framework`.

* * *

Checkout the [release](https://github.com/athena-framework/framework/releases/tag/v0.16.0) notes for a complete list of changes. As usual feel free to join me in the Athena [Gitter](https://gitter.im/athena-frameworkcr/community) channel if you have any suggestions, questions, or ideas. I’m also available on Discord (`Blacksmoke16#0016`) or via [Email](mailto:george@dietrich.app).

P.S. Athena now has a [Discord server](https://discord.gg/TmDVPb3dmr)!

---

<div class="post-metadata">

### Author: ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)
#### Post date: [January 12, 2022, 1:02pm UTC](https://forum.crystal-lang.org/t/athena-0-16-0/4251/2 "2022-01-12T13:02:16Z")

</div>

Wow, URI.decode sure seems to be slow! I sent a PR to optimize it: [Optimize URI.decode by asterite · Pull Request #11741 · crystal-lang/crystal · GitHub](https://github.com/crystal-lang/crystal/pull/11741)

What results do you get with that PR on your side?

---

<div class="post-metadata">

### Author: ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)
#### Post date: [January 12, 2022, 2:16pm UTC](https://forum.crystal-lang.org/t/athena-0-16-0/4251/3 "2022-01-12T14:16:00Z")

</div>

@asterite Whoa thanks! It deff made quite a difference! Not only did speed improve, memory per operation also was halved, and in some cases ~6x less! `URI.decode` must have also been a bottleneck in `retour` as it jumped up quite a bit as well. Given `amber` and `radix` didn’t change much I’m going to assume they’re not using it, so technically they may have an issue with matching an encoded URL, which makes the results even that much more impressive I’d say.

> **Benchmark Results w/ Optimizations**
>
> ```auto
> /get
> retour 2.52M (397.20ns) (± 1.42%) 672B/op 4.16× slower
> amber 3.20M (312.10ns) (± 1.15%) 387B/op 3.27× slower
> Athena::Routing 10.48M ( 95.46ns) (± 1.35%) 64.0B/op fastest
> radix 6.63M (150.87ns) (± 1.15%) 144B/op 1.58× slower
> 
> /get/books/23/chapters
> retour 2.01M (498.37ns) (± 2.49%) 736B/op 1.25× slower
> amber 1.21M (827.03ns) (± 1.55%) 966B/op 2.08× slower
> Athena::Routing 2.52M (397.42ns) (± 1.37%) 322B/op fastest
> radix 1.58M (632.64ns) (± 1.80%) 481B/op 1.59× slower
> 
> /get/books/23/pages
> retour 2.67M (375.00ns) (± 2.04%) 672B/op 2.82× slower
> amber 1.86M (537.34ns) (± 5.27%) 595B/op 4.04× slower
> Athena::Routing 7.52M (133.04ns) (± 3.99%) 64.0B/op fastest
> radix 1.72M (582.15ns) (± 1.93%) 416B/op 4.38× slower
> 
> /get/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z
> retour 2.30M (434.52ns) (± 2.14%) 672B/op 4.26× slower
> amber 332.26k ( 3.01µs) (± 1.38%) 4.04kB/op 29.50× slower
> Athena::Routing 9.80M (102.03ns) (± 4.70%) 64.0B/op fastest
> radix 1.90M (525.10ns) (± 1.60%) 353B/op 5.15× slower
> 
> /get/var/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6
> retour 735.58k ( 1.36µs) (± 5.60%) 1.17kB/op fastest
> amber 180.40k ( 5.54µs) (± 2.41%) 6.19kB/op 4.08× slower
> Athena::Routing 421.41k ( 2.37µs) (± 5.22%) 2.29kB/op 1.75× slower
> radix 308.44k ( 3.24µs) (± 2.67%) 2.86kB/op 2.38× slower
> 
> /get/foobarbizfoobarbizfoobarbizfoobarbizfoobarbizbat/3
> retour 1.93M (517.31ns) (± 1.61%) 768B/op 1.23× slower
> amber 1.29M (775.56ns) (± 4.63%) 864B/op 1.85× slower
> Athena::Routing 2.38M (419.42ns) (± 1.53%) 368B/op fastest
> radix 1.13M (886.71ns) (± 2.32%) 593B/op 2.11× slower
> 
> /post/products/23/reviews
> retour 1.88M (531.94ns) (± 1.12%) 768B/op 1.31× slower
> amber 1.18M (849.14ns) (± 1.78%) 1.04kB/op 2.09× slower
> Athena::Routing 2.43M (411.63ns) (± 1.37%) 369B/op 1.01× slower
> radix 2.46M (406.87ns) (± 3.62%) 450B/op fastest
> 
> /put/products/Winter-Windproof-Trapper-Hat/dp/B01J7DAMCQ
> retour 1.53M (655.02ns) (± 2.76%) 832B/op 1.25× slower
> amber 841.82k ( 1.19µs) (± 6.68%) 1.3kB/op 2.26× slower
> Athena::Routing 1.90M (524.94ns) (± 4.57%) 432B/op fastest
> 
> /get/test/foo_99
> retour 1.93M (518.98ns) (± 1.93%) 736B/op 1.24× slower
> amber 1.32M (757.77ns) (± 2.23%) 822B/op 1.80× slower
> Athena::Routing 2.38M (420.18ns) (± 2.78%) 338B/op fastest
> 
> /get/test/foo_bar
> retour 2.83M (353.24ns) (± 1.90%) 672B/op 2.88× slower
> amber 2.02M (495.22ns) (± 5.12%) 501B/op 4.04× slower
> Athena::Routing 8.15M (122.67ns) (± 1.10%) 65.0B/op fastest
> 
> ```

---

<div class="post-metadata">

### Author: ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)
#### Post date: [January 12, 2022, 4:09pm UTC](https://forum.crystal-lang.org/t/athena-0-16-0/4251/4 "2022-01-12T16:09:36Z")

</div>

Why don’t you add a sample for an encoded URL?

---

<div class="post-metadata">

### Author: ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)
#### Post date: [January 13, 2022, 12:26am UTC](https://forum.crystal-lang.org/t/athena-0-16-0/4251/5 "2022-01-13T00:26:18Z")

</div>

Good idea. Given a route like `/get/encoded/{slug}` and trying to match `/get/encoded/foo%20bar` results in:

```auto
Retour: nil
Amber: "foo bar"
Athena: "foo bar"
Radix: "foo%20bar"

```

Adding in a sample for this, excluding retour, results in:

```auto
/get/encoded/foo%20bar
          amber 1.31M (765.24ns) (± 1.68%) 1.02kB/op 1.61× slower
Athena::Routing 1.72M (583.03ns) (± 0.98%) 577B/op 1.23× slower
          radix 2.10M (475.10ns) (± 1.04%) 449B/op fastest

```

So about what I’d expect, radix is fasted since it doesn’t have the overhead of decoding it anyway.

---

<div class="post-metadata">

### Author: ![paulocoghi](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/paulocoghi/32/1429_2.png) [@paulocoghi](https://forum.crystal-lang.org/u/paulocoghi)
#### Post date: [January 13, 2022, 10:54pm UTC](https://forum.crystal-lang.org/t/athena-0-16-0/4251/6 "2022-01-13T22:54:28Z")

</div>

I am seriously considering Athena::Routing as the official routing library to our 100% Crystal framework (yet to be published)

---

<div class="post-metadata">

### Author: ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)
#### Post date: [January 13, 2022, 11:16pm UTC](https://forum.crystal-lang.org/t/athena-0-16-0/4251/7 "2022-01-13T23:16:01Z")

</div>

Nice! Glad to hear 🙂. Any questions/issues feel free to jump into the Gitter Channel/Discord Server.
