<!--toc--> |
|
## Introduction |
|
Now we will learn how to connect different URLs to their associated functions easily. |
|
When a client requests a specific URL from the HTTP server, |
it divides it into several parts (CGI variables): `SCRIPT_NAME`, `PATH_INFO` and `QUERY_STRING`. For example |
the URL `/foo/bar.php/test?x=10` is separated into: |
|
- `SCRIPT_NAME` = `/foo/bar.php` |
- `PATH_INFO` = `/test` |
- `QUERY_STRING` = `x=10` |
|
CppCMS web applications are not distributed into several |
scripts, but rather they're written using a single FastCGI application that runs on a specific "script" url, like "/myapp". So generally URLs would look like `/myapp/page/10`, where |
`SCRIPT_NAME` = "/myapp" would remain constant and `PATH_INFO` = `/page/10` is changed according to the user's needs. |
|
So the mapping between the URL and the application's member functions is done by matching a regular expression against the `PATH_INFO` part of the URL, even though this behaviour can be changed by using the `mount_point` class. |
|
This job is done by the `cppcms::url_dispatcher` class. |
|
The opposite of the dispatching is "mapping" where the names of the application parts are converted to a URLs that can be given to the user. |
|
## Code |
|
### Mapping |
|
Lets rewrite our [hello class](/wikipp/en/page/cppcms_1x_tut_hello): |
|
Since we will be routing URLs, let's include the `url_dispatcher.h` and `url_mapper.h` header file. Your include list should look like: |
|
#include <cppcms/application.h> |
#include <cppcms/service.h> |
#include <cppcms/http_response.h> |
#include <cppcms/url_dispatcher.h> |
#include <cppcms/url_mapper.h> |
#include <cppcms/applications_pool.h> |
#include <iostream> |
#include <stdlib.h> |
|
Now in our constructor, let's map some URLs to member functions: |
|
hello(cppcms::service &srv) : |
cppcms::application(srv) |
{ |
dispatcher().assign("/number/(\\d+)",&hello::number,this,1); |
mapper().assign("number","/number/{1}"); |
|
dispatcher().assign("/smile",&hello::smile,this); |
mapper().assign("smile","/smile"); |
|
dispatcher().assign("",&hello::welcome,this); |
mapper().assign(""); |
|
mapper().root("/hello"); |
} |
|
|
In the fourth line we connect the regular expression `/number/(\d+)` to the member function `number` of `this` |
instance that receives `std::string` as parameter, |
and 1st captured subexpression is passed to it (note the parameter 1 that represents the 1st subexpression as a parameter) |
and the 1st captured subexpression is passed to it (note the parameter 1 that represents the 1st subexpression as a parameter) |
|
In this case the subexpression is nonempty string that contains digits. |
In this case the subexpression is a nonempty string that contains digits. |
|
In the 5th line we create a name for this part called |
"number" and we provide a URL formatting pattern `/number/{1}` - the opposite of regular expression where `{1}` is a placeholder for the first parameter for formatting the appropriate URL. |
"number" and we provide an URL formatting pattern of `/number/{1}` - the opposite of the regular expression where `{1}` is a placeholder for the first parameter for formatting the appropriate URL. |
|
In next lines 7-8 connect member function `smile` |
In the lines 7-8 we connect the member function `smile` |
to its URL and create a mapping. Because this URL |
does not have any parameters it does not have |
any placeholders. |
|
The the line 10 we connect the empty URL to the |
`welcome` member function and in the line 11 we define default empty mapping patter for the URL. Note, because |
On line 10 we connect the empty URL to the |
`welcome` member function, and on line 11 we define the default empty mapping pattern for the URL. Note, because |
we pass only one parameter to the `assign()` function, |
we define the default URL for the application. |
|
|
In the line 13 we define the "root" of the all URLs for the |
`url_mapper` class, in our case it should be identical the |
On line 13 we define the "root" of all the URLs for the |
`url_mapper` class, in our case it should be identical to |
the `SCRIPT_NAME` CGI variable. |
|
### Description |
|
|
So when the web server receives requests that match |
a script name `/hello` it forwards them to the application: |
|
- `/hello` - `welcome` function would be called |
- `/hello/smile` - `smile` function would be called |
- `/hello/number/10` - `number` function would be called and receive a string "10" as parameter. |
|
Because the "routing table" between the URL and the |
application member functions is done we don't need |
to override the `cppcms::application::main` member |
function as it does the all dispatching for us. |
|
### Actions |
|
The "number" member function. |
|
void number(std::string num) |
{ |
int no = atoi(num.c_str()); |
response().out() << "The number is " << no << "<br/>\n"; |
response().out() << "<a href='" << url("/") << "'>Go back</a>"; |
} |
|
Note, we using `url("/")` as abstract URL for the default |
application entry point - the `/` part describes the root |
application (our single application) and the fact that |
nothing follows it shows that the default URL should be |
given - the mapping the twe `welcome` member functions |
|
In the same way we create the `smile` member function: |
|
void smile() |
{ |
response().out() << ":-) <br/>\n"; |
response().out() << "<a href='" << url("/") << "'>Go back</a>"; |
} |
|
Now we would write out `welcome` action: |
|
void welcome() |
{ |
response().out() << |
"<h1> Wellcome To Page with links </h1>\n" |
"<a href='" << url("/number",1) << "'>1</a><br>\n" |
"<a href='" << url("/number",15) << "'>15</a><br>\n" |
"<a href='" << url("/smile") << "' >:-)</a><br>\n"; |
} |
|
Note, we show three URLs to the different application |
parts: "number" - and we would pass a parameter `1` to the `cppcms::application::url` function that would be rendered instead of the placeholder `{1}`, we do the same for |
number 15 and pass a URL to "smile" part without parameters. |
|
Lets describe in the example the actions that are taken for when we call `url("/number",15)`: |
|
- First for "/" we go to the topmost application, in out case to `this` one. |
- Next we match "number" against the known pattern "number" that was mapped to `"/number/{1}"`. |
- We fetch the pattern and use the parameter that is passed to `url` function and convert: `/number/{1}` to `/number/15`. |
- Finally we perpend the root URL path "/hello" and get our final URL `/hello/number/15`. |
|
Note: the parameters to `url` family of functions can be anything that can be written to `std::ostream` - i.e. any object that defined operator `<<` with standard C++ streams. |
|
## Running The Example |
|
Recompile it: |
|
c++ hello.cpp -lcppcms -o hello |
|
And now for the exciting part, start your application: |
|
./hello -c config.js |
|
And hit the URL: <http://localhost:8080/hello> |