Skip to content

Request Handlers

Farzad Habibi edited this page Dec 22, 2019 · 5 revisions

As mentioned above, any Route may have some handlers to handle incoming requests. Any request handler should be a class derived from RequestHandler class:

class RequestHandler {
public:
  virtual Response *callback(Request *req) = 0;
};

RequestHandler is a pure abstract class that has only one function: callback, which should be overridden.

Serving Static Files

Some useful request handlers or serving static files are provided in the library:

  • ShowFile: takes filePath and fileType(MIME type) parameters in its constructor and serves the related file

  • ShowPage: takes a filePath parameter in it's constructor and serves text page, specially an .html page

  • ShowImage: takes a filePath parameter in its constructor and serves image

Also, you can write your own handlers.

Serving Dynamic Files

You should write your own request handler to dynamic server pages. Your handler should inherit from RequestHandler class and override callback function. callback function takes a Request *, which comes from client-side, and give a Response *, which will be sent to client-side. You should create an appropriate Response * and return it while overriding this function.

This is an example which serves a dynamic html page:

class RandomNumberHandler : public RequestHandler {
public:
  Response *callback(Request *req) {
    Response *res = new Response;
    res->setHeader("Content-Type", "text/html");
    string body;
    body += "<!DOCTYPE html>";
    body += "<html>";
    body += "<body style=\"text-align: center;\">";
    body += "<h1>AP HTTP</h1>";
    body += "<p>";
    body += "a random number in [1, 10] is: ";
    body += to_string(rand() % 10 + 1);
    body += "</p>";
    body += "</body>";
    body += "</html>";
    res->setBody(body);
    return res;
  }
};

Getting Data from Client-side

To get data from the client-side, especially using a POST request, you should write your handler, too. You should return a Response * as well at the end of the callback function. Sometimes you should redirect the client to a new address after handling the POST request.

Redirection

You may want to redirect the client to a new page when handling a request, especially after handling a POST request. Response::redirect(std::string url) is a static function of Response class which returns a Response * which will redirects client to url and can be returned in a RequestHandler::callback.

class LoginHandler : public RequestHandler {
public:
  Response *callback(Request *req) {
    string username = req->getBodyParam("username");
    string password = req->getBodyParam("password");
    // do something with username and password
    return Response::redirect("/");
  }
};

Serving Template Files

You should write your own TemplateHandler to serve template files. This class extended from RequestHandler and implemented it's callback function. You should implement handle method. This method gets a Request* to have access to client data like other handlers, and it returns a map<string, string> . You have access to this map with the name context in the template file.

map<string, string> ColorHandler::handle(Request *req) {
  map<string, string> context;
  string newName = "I am " + req->getQueryParam("name");
  context["name"] = newName;
  context["color"] = req->getQueryParam("color");
  return context;
}

Template Files

Template file system makes it possible to separate c++ and HTML, the c++ goes in TemplateHandlers and HTML goes in templates. You can have some c++ code between <% and %> tags in html files. For example, to show our name in a custom color from the previous example, you can have something like this.

<html>
  <body>
    <%
      if(context["color"] == "red")
      {
    %>
    <div style="color:red;">
      <%
        cout << context["name"];
      %>
    </div>
    <%
      }
    %>
  </body>
</html>

NOTES:

  • You have access to iostream and string includes in template files.
  • Do not use dependent codes in seprate blocks. Like an if in one code block and it's else if in other code block.

Throwing Exceptions

You can throw Server::Exception inside request handlers, which will be shown as JSON error responses.

AP HTTP

Clone this wiki locally