View Source Antikythera.Router (antikythera v0.5.1)
Defines the antikythera routing DSL.
Routing macros
This module defines macros to be used in each gear's Router module.
The names of the macros are the same as the HTTP verbs: get
, post
, etc.
The macros take the following 4 arguments (although you can omit the last and just pass 3 of them):
- URL path pattern which consists of '/'-separated segments. The 1st character must be '/'. To match against incoming request path to a pattern you can use placeholders. See examples below for the usage.
- Controller module.
Antikythera expects that the module name given here does not contain
GearName.Controller.
as a prefix; it's automatically prepended by antikythera. - Name of the controller action as an atom.
- Keyword list of options.
Currently available options are
:from
and:as
. See below for further explanations.
Example
If you define the following router module,
defmodule MyGear.Router do
use Antikythera.Router
static_prefix "/static"
websocket "/ws"
get "/foo" , Hello, :exact_match
post "/foo/:a/:b" , Hello, :placeholders
put "/foo/bar/*w", Hello, :wildcard
end
Then the following requests are routed as:
GET "/foo"
=>MyGear.Controller.Hello.exact_match/1
is invoked withpath_matches
:%{}
POST "/foo/bar/baz"
=>MyGear.Controller.Hello.placeholders/1
is invoked withpath_matches
:%{a: "bar", b: "baz"}
PUT "/foo/bar/abc/def/ghi"
=>MyGear.Controller.Hello.wildcard/1
is invoked withpath_matches
:%{w: "abc/def/ghi"}
Note that
- Each controller action is expected to receive a
Antikythera.Conn
struct and returns aAntikythera.Conn
struct. Antikythera.Conn
struct has a fieldrequest
which is aAntikythera.Request
struct.- Matched segments are URL-decoded and stored in
path_matches
field inAntikythera.Request
. If the result of URL-decoding is nonprintable binary, the request is rejected.
Websocket endpoint
To enable websocket interaction with clients, you must first define MyGear.Websocket
module.
See Antikythera.Websocket
for more details about websocket handler module.
Then invoke websocket/1
macro in your router.
websocket "/ws_path_pattern"
The path pattern may have placeholders in the same way as normal routes. GET request with appropriate headers to this path will initialize a websocket connection using the HTTP 1.1 upgrade mechanism.
If your gear does not interact with clients via websocket, simply don't invoke websocket/1
macro in your router.
Static file serving
You can serve your static assets by placing them under /priv/static
directory in your gear project.
The endpoint to be used can be specified by static_prefix/1
macro.
For example, if you add
static_prefix "/assets"
to your router, you can download /priv/static/html/index.html
file by sending GET request to the path /assets/html/index.html
.
If you don't need to serve static assets, just don't call static_prefix/1
macro in your router.
Currently, static assets served in this way are NOT automatically gzip compressed,
even if acceept-encoding: gzip
request header is set.
It is recommended to use CDN to deliver large static assets in production.
See also Antikythera.Asset
for usage of CDN in delivery of static assets.
Web requests and gear-to-gear (g2g) requests
Antikythera treats both web requests and g2g requests in basically the same way.
This means that if you define a route in your gear one can send request to the route using both HTTP and g2g communication.
If you want to define a route that can be accessible only via g2g communication, specify from: :gear
option.
get "/foo", Hello, :action1, from: :gear
post "/bar", Hello, :action2, from: :gear
Similarly passing from: :web
makes the route accessible only from web request.
When dealing with multiple routes, only_from_web/1
and only_from_gear/1
macros can be used.
For example, the following routes definition is the same as above one.
only_from_gear do
get "/foo", Hello, :action1
post "/bar", Hello, :action2
end
Reverse routing
To generate URL path of a route (e.g. a link in HTML), you will want to refer to the route's path.
For this purpose you can specify :as
option.
For example, you have the following router module
defmodule MyGear.Router do
use Antikythera.Router
get "/foo/:a/:b/*c", Hello, :placeholders, as: :myroute
end
By writing this the router automatically defines a function myroute_path/4
,
which receives segments that fill placeholders and an optional map for query parameters.
MyGear.Router.myroute_path("segment_a", "segment_b", ["wildcard", "part"])
=> "/foo/segment_a/segment_b/wildcard/part
MyGear.Router.myroute_path("segment_a", "segment_b", ["wildcard", "part"], %{"query" => "param"})
=> "/foo/segment_a/segment_b/wildcard/part?query=param
Reverse routing helper functions automatically URI-encode all given arguments.
If websocket endpoint is enabled, you can get its path with MyGear.Router.websocket_path/0
.
Also if static file serving is enabled, path prefix for static files can be obtained by MyGear.Router.static_prefix/0
.
Per-API timeout
You can specify timeout for each API by :timeout
option.
The timeout is specified in milliseconds.
For example, the following API times out after 60 seconds.
get "/foo", Hello, :long_action, timeout: 60_000
The maximum timeout is determined by :gear_action_max_timeout
configuration in config/config.exs
.
The default value is 10 seconds, which can be configured by GEAR_ACTION_TIMEOUT
environment variable.