Did you know ... | Search Documentation: |
Packs (add-ons) for SWI-Prolog |
Title: | Alternative HTTP path router |
---|---|
Rating: | Not rated. Create the first rating! |
Latest version: | 2.0.0 |
SHA1 sum: | d6b5fde196c0b3e7935d696c34ae52a1130266bc |
Author: | Raivo Laanemets http://rlaanemets.com/ |
Home page: | https://github.com/rla/alternative-router |
No reviews. Create the first review!.
Version | SHA1 | #Downloads | URL |
---|---|---|---|
0.0.1 | 2cca79ac4c26b542853e0720a6347379dba07d8b | 2 | http://packs.rlaanemets.com/alternative-router/arouter-0.0.1.tgz |
1.0.0 | 2a8f103bd01002a14dda67e92c61255699db9a29 | 6 | https://github.com/honnix/alternative_router.git |
830a2eb869d9e48a8e230de18137d17016086e77 | 32 | http://packs.rlaanemets.com/alternative-router/arouter-1.0.0.tgz | |
1.1.1 | b1d2f6ca0076c1ecce33b511a816fc48ad3172bf | 6 | https://github.com/honnix/alternative_router.git |
b9639e19ebc606060a98ffc8ea12da9061f807fd | 134 | http://packs.rlaanemets.com/alternative-router/arouter-1.1.1.tgz | |
2.0.0 | d6b5fde196c0b3e7935d696c34ae52a1130266bc | 57 | http://packs.rlaanemets.com/alternative-router/arouter-2.0.0.tgz |
This is an alternative router/dispatcher to Swi-Prolog's http_dispatch module. The main motivation for creating this module was more convenient (less verbose) implementation of RESTful web services.
![Build Status](https://travis-ci.org/rla/alternative-router)
:- use_module(library(http/thread_httpd)). :- use_module(library(arouter)). :- route_get(hello/Name, handle_hello(Name)). handle_hello(Name):- format('Content-Type: text/plain; charset=UTF-8~n~n'), format('Hello ~w', [Name]). :- http_server(route, [port(8008)]).
Save it to a file, run it, and then visit http://localhost:8008/hello/world.
Normal path terms correspond directly to URL paths with the implicit root (/
)
symbol. For example, path/to/something
corresponds to URL
`http://example.com/path/to/something`. To match the root itself, /
alone
must be used. To match an URL path with a slash in the end, an empty atom
has to be used at the end of the path term. For example, to match URL
`http://example.com/path/to/something/`, a path term path/to/something/''
must be used.
Make fallback to http_dispatch/1 like this:
handle_request(Request):- ( route(Request) -> true ; http_dispatch(Request)).
and use handle_request/1 as the handler in http_server
.
Routes can have intermediate goals. The following example is cheking auth information before executing the handler:
:- route_get(api/resource, auth, handle_resource). auth(Next):- ( http_session_data(user(User)), memberchk(role(admin), User) -> call(Next) ; current_request(Request), memberchk(path(Path), Request), current_output(Out), http_reply(forbidden(Path), Out, [])). handle_resource:- ...
The before-handler predicate calls its first argument when the request should pass it. Otherwise it should produce the response itself.
A path will match the route when:
/
./(P1, P2)
, route is /(R1, R2)
and R1 matches P1 and R2 matches P2.Routes are tested in reverse to the adding order. Overlapping routes can be added. Structurally equivalent routes cannot be added. Routes are overlapping when one route has atom in position of route variable in the other. Routes are structurally equivalent when:
/
./(A1, B1)
, the other is /(A2, B2)
and
A1, A2 are structurally equivalent and B1, B2 are structurally equivalent.Structural equivalence is used for detecting duplicate rules. This plays nice with the make/0 goal.
In some cases another matching (overlapping) route might have to be tried. This can be
done by throwing arouter_next
from the current route handler. Example:
:- route_get(something/specific, handle_specific). handle_specific:- ... :- route_get(something/Generic, handle_generic(Generic)). handle_generic(Generic):- ( Generic = specific -> throw(arouter_next) ; ...).
The handler handle_specific
will handle the request in this case
after throwing arouter_next
from the handle_generic
handler (handlers
are tried in reverse order of adding them).
`route_get(+Route, :Goal)` registers a new GET handler.
`route_put(+Route, :Goal)` registers a new PUT handler.
`route_del(+Route, :Goal)` registers a new DELETE handler.
`route_post(+Route, :Goal)` registers a new POST handler.
`route_get(+Route, :Before, :Goal)` registers a new GET handler with a before action.
`route_put(+Route, :Before, :Goal)` registers a new PUT handler with a before action.
`route_del(+Route, :Before, :Goal)` registers a new DELETE handler with a before action.
`route_post(+Route, :Before, :Goal)` registers a new POST handler with a before action.
`new_route(+Method, +Route, :Goal)` registers a new custom method handler.
`new_route(+Method, +Route, :Before, :Goal)` registers a new custom method handler with a before action.
All predicates above will throw an error when the Route does not contain the suitable term.
Route handler predicates can take variables from the route. Example:
:- http_get(post/show/Slug, post_show(Slug)). post_show(Slug):- ...
However, they do not take the Request argument, unlike the http_dispatch
handlers. To obtain the
current request, use the http_current_request/1
predicate.
route(+Request)
- takes given request and attempts to find suitable handler.
Request must contain terms method(Method)
and path(Path)
. Throws handler_failed(Method, Path)
when
handler was found but it failed during execution.
Use the `route(?Method, ?Route, ?Before, ?Goal)` predicate.
Use the route_remove(Method, Route)
predicate. Both arguments
can be unbound or partially instantiated.
To install as a package:
pack_install(arouter).
Tested with Swi-Prolog 7.x but should work with earlier versions too.
See http://packs.rlaanemets.com/alternative-router/doc/.
In the package root, insert into swipl:
[tests/tests]. run_tests.
Or if you cloned the repo:
make test
Enable debugging with:
?- use_module(library(debug)). ?- debug(arouter).
make
.Please send bug reports/feature request through the GitHub project page.
The MIT license. See the LICENSE file.
Pack contains 7 files holding a total of 22.2K bytes.