<!--toc--> |
|
## General |
|
The basic approach of mapping an URL to a member function of our class works well for small applications, but can become problematic for complex systems. |
|
CppCMS allows you to create a hierarchy of applications that work as a single unit. You connect them by using the `url_mapper` and `url_dispatcher` classes. |
|
Before you read this tutorial, please read [URL Dispatching and Mapping](/wikipp/en/page/cppcms_1x_tut_url_mapping) tutorial. |
|
## Example |
|
### Hierarchy |
|
We will create a very simple example of an "educational" application, that consists of two sub-applications: |
|
- myapp - main application |
- numbers - display different numbers: |
- all |
- odd |
- even |
- prime |
- letters - display different letters: |
- all |
- capital |
- small |
|
We will create 3 classes where `myapp` would be the topmost class in the hierarchy, and `numbers` and `letters` would be sub-applications. |
|
### Sub-Applications |
|
Let's define our sub-applications: |
|
class numbers : public cppcms::application { |
public: |
|
The constructor: |
|
numbers(cppcms::service &srv) : cppcms::application(srv) |
{ |
dispatcher().assign("",&numbers::all,this); |
mapper().assign(""); |
|
dispatcher().assign("/odd",&numbers::odd,this); |
mapper().assign("odd","/odd"); |
|
dispatcher().assign("/even",&numbers::even,this); |
mapper().assign("even","/even"); |
|
dispatcher().assign("/prime",&numbers::prime,this); |
mapper().assign("prime","/prime"); |
} |
|
Create default application URL - all, and connect 4 member functions `odd`, `even`, `prime` and `all` to it, such that: |
|
void prime() |
{ |
response().out() << "2,3,5,7,..."; |
} |
void odd() |
{ |
response().out() << "1,3,5,7,9,..."; |
} |
void even() |
{ |
response().out() << "2,4,6,8,10,..."; |
} |
|
Now let's create our `all` member function that would |
include links to different modules: |
|
void all() |
{ |
response().out() |
<< "<a href='" << url("/") << "'>Top</a><br>" |
<< "<a href='" << url("/letters")<< "'>Letters</a><br>" |
<< "<a href='" << url(".") << "'>All Numbers</a><br>" |
<< "<a href='" << url("odd") << "'>Odd Numbers</a><br>" |
<< "<a href='" << url("even") << "'>Even Numbers</a><br>" |
<< "<a href='" << url("prime") << "'>Prime Numbers</a><br>" |
<< "1,2,3,4,5,6,7,8,9,10,..."; |
} |
|
|
Note: |
|
- `url("/")` - points to the default location of the topmost application. The `numbers` application does not need to know what that is. |
- `url("/letters")` - points to the default location of the sub-application letters starting from the root. |
- `url(".")` - points to the default handling for the current application. |
- `url("odd")`, `url("even")`, `url("prime")` - point |
to current application's different parts. |
|
|
Now we create a similar class for `letters` |
class letters : public cppcms::application { |
public: |
|
Constructor: |
|
letters(cppcms::service &srv) : cppcms::application(srv) |
{ |
dispatcher().assign("",&letters::all,this); |
mapper().assign(""); |
|
dispatcher().assign("/capital",&letters::capital,this); |
mapper().assign("capital","/capital"); |
|
dispatcher().assign("/small",&letters::small,this); |
mapper().assign("small","/small"); |
|
} |
|
Member functions: |
|
void all() |
{ |
response().out() |
<< "<a href='" << url("/") << "'>Top</a><br>" |
<< "<a href='" << url("/numbers")<< "'>Numbers</a><br>" |
<< "<a href='" << url(".") << "'>All Letters</a><br>" |
<< "<a href='" << url("capital") << "'>Capital Letters</a><br>" |
<< "<a href='" << url("small") << "'>Small Letters</a><br>" |
<< "Aa, Bb, Cc, Dd,..."; |
} |
|
void capital() |
{ |
response().out() << "A,B,C,D,..."; |
} |
void small() |
{ |
response().out() << "a,b,c,d,..."; |
} |
|
### Main Application |
|
Now lets create our topmost application: |
|
class myapp: public cppcms::application { |
public: |
|
Constructor: |
|
myapp(cppcms::service &srv) : |
cppcms::application(srv) |
{ |
attach( new numbers(srv), |
"numbers", "/numbers{1}", // mapping |
"/numbers(/(.*))?", 1); // dispatching |
attach( new letters(srv), |
"letters", "/letters{1}", // mapping |
"/letters(/(.*))?", 1); // dispatching |
|
dispatcher().assign("",&myapp::describe,this); |
mapper().assign(""); // default URL |
|
mapper().root("/myapp"); |
} |
|
Note: we call `attach` member function with following parameters: |
|
new numbers(srv) |
|
New sub-application - we pass the ownership to the parent so we don't need to handle its lifetime on our own. |
|
"numbers", "/numbers{1}" |
|
Mapping - application named "numbers" is mapped according |
the the pattern "/numbers{1}" - such that each sub application's URL would replace the `{1}` placeholder. |
|
|
"/numbers(/(.*))?", 1) |
|
The regular expression pattern for matching the sub-application. Note, unlike with member functions, exactly one sub-expression is expected - this captured subexpression is passed to the child's main function for further dispatching. |
|
The same is done for the `letters` and `myapp` member functions. |
|
Now lets analyze how an HTTP request `GET /myapp/numbers/prime` is parsed. |
|
1. The web server splits `/myapp/numbers/prime` to `/myapp` as `SCRIPT_NAME` and `/numbers/prime` as `PATH_INFO` |
2. `myapp` matches `/numbers/prime` against the `/numbers(/(.*))?` expression, and extracts `/prime` as the subexpression that is passed to `numbers`'s main function. |
3. `/prime` is matched against `/prime` expression and `numbers::prime` function is called. |
|
|
Now lets show the final touch - the `describe` function of `myapp`: |
|
|
|
void describe() |
{ |
response().out() |
<< "<a href='" << url("/numbers")<< "'>Numbers</a><br>" |
<< "<a href='" << url("/letters")<< "'>Letters</a><br>" |
<< "<a href='" << url("/numbers/odd")<< "'>Odd Numbers</a><br>"; |
} |
|
URL("/numbers") - relates to the default URL of the "numbers" sub-application, and similar for `letters`. The URL("/numbers/odd`) refers to "odd" mapping of the "numbers" sub-application. Let's see how the mapping is done in detail. |
|
1. A path `/numbers/odd` is split into "numbers" and "odd" tokens. |
2. We search for "numbers" sub-application and find it. |
3. In `numbers`'s sub-application mapper we search for "odd" mapping and find it. |
4. We construct all backward: |
|
- "odd" -> "/odd" |
- "/numbers{1}" + "/odd" -> "/numbers/odd" |
- Root "/myapp" + "/numbers/odd" -> "/myapp/numbers/odd" |
|
|
So we fully connect our main applications and sub-applications using some generic names. |
|
|
## Running |
|
Finally let's add the main function |
|
int main(int argc,char ** argv) |
{ |
try { |
cppcms::service app(argc,argv); |
app.applications_pool().mount(cppcms::applications_factory<myapp>()); |
app.run(); |
} |
catch(std::exception const &e) { |
std::cerr<<e.what()<<std::endl; |
} |
} |
|
|
Create the configuration file: |
|
{ |
"service" : { |
"api" : "http", |
"port" : 8080 |
}, |
"http" : { |
"script" : "/myapp" |
} |
} |
|
|
Build and run as: |
|
./myapp -c config.js |
|
And hit the URL: <http://localhost:8080/myapp> |
|
|
|
<!--toc-->
|
|
## General
|
|
The basic approach of mapping an URL to a member function of our class works well for small applications, but can become problematic for complex systems.
|
|
CppCMS allows you to create a hierarchy of applications that work as a single unit. You connect them by using the `url_mapper` and `url_dispatcher` classes.
|
|
Before you read this tutorial, please read [URL Dispatching and Mapping](/wikipp/en/page/cppcms_1x_tut_url_mapping) tutorial.
|
|
## Example
|
|
### Hierarchy
|
|
We will create a very simple example of an "educational" application, that consists of two sub-applications:
|
|
- myapp - main application
|
- numbers - display different numbers:
|
- all
|
- odd
|
- even
|
- prime
|
- letters - display different letters:
|
- all
|
- capital
|
- small
|
|
We will create 3 classes where `myapp` would be the topmost class in the hierarchy, and `numbers` and `letters` would be sub-applications.
|
|
### Sub-Applications
|
|
Let's define our sub-applications:
|
|
class numbers : public cppcms::application {
|
public:
|
|
The constructor:
|
|
numbers(cppcms::service &srv) : cppcms::application(srv)
|
{
|
dispatcher().assign("",&numbers::all,this);
|
mapper().assign("");
|
|
dispatcher().assign("/odd",&numbers::odd,this);
|
mapper().assign("odd","/odd");
|
|
dispatcher().assign("/even",&numbers::even,this);
|
mapper().assign("even","/even");
|
|
dispatcher().assign("/prime",&numbers::prime,this);
|
mapper().assign("prime","/prime");
|
}
|
|
Create default application URL - all, and connect 4 member functions `odd`, `even`, `prime` and `all` to it, such that:
|
|
void prime()
|
{
|
response().out() << "2,3,5,7,...";
|
}
|
void odd()
|
{
|
response().out() << "1,3,5,7,9,...";
|
}
|
void even()
|
{
|
response().out() << "2,4,6,8,10,...";
|
}
|
|
Now let's create our `all` member function that would
|
include links to different modules:
|
|
void all()
|
{
|
response().out()
|
<< "<a href='" << url("/") << "'>Top</a><br>"
|
<< "<a href='" << url("/letters")<< "'>Letters</a><br>"
|
<< "<a href='" << url(".") << "'>All Numbers</a><br>"
|
<< "<a href='" << url("odd") << "'>Odd Numbers</a><br>"
|
<< "<a href='" << url("even") << "'>Even Numbers</a><br>"
|
<< "<a href='" << url("prime") << "'>Prime Numbers</a><br>"
|
<< "1,2,3,4,5,6,7,8,9,10,...";
|
}
|
|
|
Note:
|
|
- `url("/")` - points to the default location of the topmost application. The `numbers` application does not need to know what that is.
|
- `url("/letters")` - points to the default location of the sub-application letters starting from the root.
|
- `url(".")` - points to the default handling for the current application.
|
- `url("odd")`, `url("even")`, `url("prime")` - point
|
to current application's different parts.
|
|
|
Now we create a similar class for `letters`
|
class letters : public cppcms::application {
|
public:
|
|
Constructor:
|
|
letters(cppcms::service &srv) : cppcms::application(srv)
|
{
|
dispatcher().assign("",&letters::all,this);
|
mapper().assign("");
|
|
dispatcher().assign("/capital",&letters::capital,this);
|
mapper().assign("capital","/capital");
|
|
dispatcher().assign("/small",&letters::small,this);
|
mapper().assign("small","/small");
|
|
}
|
|
Member functions:
|
|
void all()
|
{
|
response().out()
|
<< "<a href='" << url("/") << "'>Top</a><br>"
|
<< "<a href='" << url("/numbers")<< "'>Numbers</a><br>"
|
<< "<a href='" << url(".") << "'>All Letters</a><br>"
|
<< "<a href='" << url("capital") << "'>Capital Letters</a><br>"
|
<< "<a href='" << url("small") << "'>Small Letters</a><br>"
|
<< "Aa, Bb, Cc, Dd,...";
|
}
|
|
void capital()
|
{
|
response().out() << "A,B,C,D,...";
|
}
|
void small()
|
{
|
response().out() << "a,b,c,d,...";
|
}
|
|
### Main Application
|
|
Now lets create our topmost application:
|
|
class myapp: public cppcms::application {
|
public:
|
|
Constructor:
|
|
myapp(cppcms::service &srv) :
|
cppcms::application(srv)
|
{
|
attach( new numbers(srv),
|
"numbers", "/numbers{1}", // mapping
|
"/numbers(/(.*))?", 1); // dispatching
|
attach( new letters(srv),
|
"letters", "/letters{1}", // mapping
|
"/letters(/(.*))?", 1); // dispatching
|
|
dispatcher().assign("",&myapp::describe,this);
|
mapper().assign(""); // default URL
|
|
mapper().root("/myapp");
|
}
|
|
Note: we call `attach` member function with following parameters:
|
|
new numbers(srv)
|
|
New sub-application - we pass the ownership to the parent so we don't need to handle its lifetime on our own.
|
|
"numbers", "/numbers{1}"
|
|
Mapping - application named "numbers" is mapped according
|
the the pattern "/numbers{1}" - such that each sub application's URL would replace the `{1}` placeholder.
|
|
|
"/numbers(/(.*))?", 1)
|
|
The regular expression pattern for matching the sub-application. Note, unlike with member functions, exactly one sub-expression is expected - this captured subexpression is passed to the child's main function for further dispatching.
|
|
The same is done for the `letters` and `myapp` member functions.
|
|
Now lets analyze how an HTTP request `GET /myapp/numbers/prime` is parsed.
|
|
1. The web server splits `/myapp/numbers/prime` to `/myapp` as `SCRIPT_NAME` and `/numbers/prime` as `PATH_INFO`
|
2. `myapp` matches `/numbers/prime` against the `/numbers(/(.*))?` expression, and extracts `/prime` as the subexpression that is passed to `numbers`'s main function.
|
3. `/prime` is matched against `/prime` expression and `numbers::prime` function is called.
|
|
|
Now lets show the final touch - the `describe` function of `myapp`:
|
|
|
|
void describe()
|
{
|
response().out()
|
<< "<a href='" << url("/numbers")<< "'>Numbers</a><br>"
|
<< "<a href='" << url("/letters")<< "'>Letters</a><br>"
|
<< "<a href='" << url("/numbers/odd")<< "'>Odd Numbers</a><br>";
|
}
|
|
URL("/numbers") - relates to the default URL of the "numbers" sub-application, and similar for `letters`. The URL("/numbers/odd`) refers to "odd" mapping of the "numbers" sub-application. Let's see how the mapping is done in detail.
|
|
1. A path `/numbers/odd` is split into "numbers" and "odd" tokens.
|
2. We search for "numbers" sub-application and find it.
|
3. In `numbers`'s sub-application mapper we search for "odd" mapping and find it.
|
4. We construct all backward:
|
|
- "odd" -> "/odd"
|
- "/numbers{1}" + "/odd" -> "/numbers/odd"
|
- Root "/myapp" + "/numbers/odd" -> "/myapp/numbers/odd"
|
|
|
So we fully connect our main applications and sub-applications using some generic names.
|
|
|
## Running
|
|
Finally let's add the main function
|
|
int main(int argc,char ** argv)
|
{
|
try {
|
cppcms::service app(argc,argv);
|
app.applications_pool().mount(cppcms::applications_factory<myapp>());
|
app.run();
|
}
|
catch(std::exception const &e) {
|
std::cerr<<e.what()<<std::endl;
|
}
|
}
|
|
|
Create the configuration file:
|
|
{
|
"service" : {
|
"api" : "http",
|
"port" : 8080
|
},
|
"http" : {
|
"script" : "/myapp"
|
}
|
}
|
|
|
Build and run as:
|
|
./myapp -c config.js
|
|
And hit the URL: <http://localhost:8080/myapp>
|
|
|
|
|