Serving Static Files and Single Page Applications on Oat++ (OatPP)

Oat++(OatPP) is a lightweight C++ Web framework. Out of the box, it provides REST API with built-in JSON serialization/deserialization features, which could be interfaced with your DTOs.

It also offers various modules that could be easily added and us…


This content originally appeared on DEV Community and was authored by Mehmet YILMAZ

Oat++(OatPP) is a lightweight C++ Web framework. Out of the box, it provides REST API with built-in JSON serialization/deserialization features, which could be interfaced with your DTOs.

It also offers various modules that could be easily added and used in your application in a plug-in manner.

Since the main concept of the framework is RestAPI, it does not provide static file serving as default. It means that you must implement your solution to serve your static resources over the Oat++ Web server.

Despite sounding a little scary, it is not difficult at all. With the help of the frameworks Oatpp::String::loadFromFile method, we can easily implement our solution.

Before getting started we can list the steps that we will follow below;

  1. Create a public static folder and files
  2. File Mime Content Type Mapping
  3. Define Endpoints

1- Create a public static folder and files

This folder will be used to serve static sources and will be accessible over the HTTP Protocol. So we can store our HTML, JS, CSS files, images, etc.

I will create my folder directly under the project root folder and name it as public in my example. Create a simple HTML file, a simple JS file, a simple CSS file, a favicon, and an image to simulate the widely used content types in order the following folder tree.

Folder tree

ProjectRoot/
├─ public/
│  ├─ favicon.ico
│  ├─ index.html
│  ├─ index.js
│  ├─ style.css
│  ├─ images/
│  │  ├─ logo.svg

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" href="favicon.ico">
    <script src="index.js"></script>
    <link rel="stylesheet" href="style.css">
    <title>Oat++ Static File Serving Example</title>
</head>
<body>
    <div class="container">
        <div class="header">
            <img src="images/logo.png" alt="Logo">
            <h1>
                Oat++
            </h1>
            <p id="counter"> </p>
        </div>
        <div class="main">
            <button id="clicker" onclick="onCount()">Count</button>
        </div>
        <div class="footer"></div>
    </div>
</body>
</html>

index.js

var iterator = 0;
var counter = document.getElementById("counter");
function onCount() {
  counter.innerText = iterator++;
  console.log("Counter Increased: ", iterator);
};

style.css

body {
  background-color: bisque;
  color: black;
}

.header {
display: block;
}

Images

An .ico file as a favicon, and an image as a logo.

favicon would be stored in the static folder according to my HTML file and logo under the images folder which is a sub-folder of the public.

2. File Mime Content Type Mapping

Web servers usually provide a public folder, like www where you can store your static resources via S/FTP, WebUI, SSH, etc.
Or you can set your dedicated folder as a static resources folder accessible over HTTP.

So, if you have an index.html file in your static folder, you can access it over HTTP via http://localhost:port/index.html. All the other files located in the static folder would be accessible with the same path structure as well. For example, we can access the logo.png file under the images folder via this URL: http://localhost:port/images/logo.png

This is what we are looking for, right? We are almost there.
We also need a content-type mapper to respond correctly with files regarding its extension.

I will shortly create a sample function that expects the path and finds the extension by easily looking after the last. in the path and return the correct content type.

To create a full mime content type, you can reference NGINX’s map linked below.
https://github.com/nginx/nginx/blob/master/conf/mime.types

std::string* getContentType(const std::string &path) {
  const size_t i = path.find_last_of(".");
  if (i != std::string::npos) {
    const std::string extension = path.substr(i+1); 
    if(extension == "html" || extension == "htm" || extension == "shtml")
      return "text/html";
    if (extension == "js")
      return "application/javascript";
    if (extension == "css")
      return "text/css";
    if (extension == "jpg" || extension == "jpg")
      return "image/jpeg";
    if (extension == "gif")
      return "image/gif";
    if (extension == "ico")
      return "image/x-icon";
    if (extension == "png")
      return "image/png";
    if (extension == "svg" || extension == "svgz")
      return "image/svg+xml";
  }
    return nullptr; // if the path has no "." or has unknow extension we can not find the correct mime as well.
};

3. Defining Endpoints

The best way of serving static files is by defining a wildcard endpoint at the end of the routes.

Open your last controller or better create one for static routes and add it to the router as the last controller to prevent any unexpected bypass of API endpoints.
I am working on async but you can easily refactor the code in your regular endpoint.

In the following example, we will accept the wildcard route and check;

We will respond with the index.html for route (/) endpoint.
Try to read the file, and respond with 404 in case of not found.
If we find the file, then check the content type regarding its extension and add the content-type header with its mapped mime in the response.

You can also change the code and respond with the index.html for not-found files to Single-Page Application compatibility.

static-controller

ENDPOINT_ASYNC("GET", "*", Wildcard)
  {
      ENDPOINT_ASYNC_INIT(Wildcard)
      Action act() override
      {
          std::string path = request->getPathTail();
          // Load the home page in case of no path, it means calling root like: http://localhost/
          if (path.empty()) {
             path = "index.html"; // This is my default home file, you can set your own home page as well.
          }
          // We will check the file if exist and send the index.html in case of not 
          auto file = oatpp::String::loadFromFile(path.c_srt());
          // Send 404 not found in case of no file
          OATPP_ASSERT_HTTP(file.get() != nullptr, Status::CODE_404, "File not found");

          // As file already found, we can search the content type
          const std::string* contentType = getContentType(path);

          // Creating the response
          auto response = this->controller->createResponse(Status::CODE_200, file);
          if(contentType != nullptr) // Add the content-type header only if we have a known mime
            res->putHeader(Header::CONTENT_TYPE, *contentType);
          return _return(response);
      };
  };

This is the basic implementation and simple example of serving static files over Oat++ and I hope will help you.


This content originally appeared on DEV Community and was authored by Mehmet YILMAZ


Print Share Comment Cite Upload Translate Updates
APA

Mehmet YILMAZ | Sciencx (2024-07-23T21:16:57+00:00) Serving Static Files and Single Page Applications on Oat++ (OatPP). Retrieved from https://www.scien.cx/2024/07/23/serving-static-files-and-single-page-applications-on-oat-oatpp/

MLA
" » Serving Static Files and Single Page Applications on Oat++ (OatPP)." Mehmet YILMAZ | Sciencx - Tuesday July 23, 2024, https://www.scien.cx/2024/07/23/serving-static-files-and-single-page-applications-on-oat-oatpp/
HARVARD
Mehmet YILMAZ | Sciencx Tuesday July 23, 2024 » Serving Static Files and Single Page Applications on Oat++ (OatPP)., viewed ,<https://www.scien.cx/2024/07/23/serving-static-files-and-single-page-applications-on-oat-oatpp/>
VANCOUVER
Mehmet YILMAZ | Sciencx - » Serving Static Files and Single Page Applications on Oat++ (OatPP). [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/07/23/serving-static-files-and-single-page-applications-on-oat-oatpp/
CHICAGO
" » Serving Static Files and Single Page Applications on Oat++ (OatPP)." Mehmet YILMAZ | Sciencx - Accessed . https://www.scien.cx/2024/07/23/serving-static-files-and-single-page-applications-on-oat-oatpp/
IEEE
" » Serving Static Files and Single Page Applications on Oat++ (OatPP)." Mehmet YILMAZ | Sciencx [Online]. Available: https://www.scien.cx/2024/07/23/serving-static-files-and-single-page-applications-on-oat-oatpp/. [Accessed: ]
rf:citation
» Serving Static Files and Single Page Applications on Oat++ (OatPP) | Mehmet YILMAZ | Sciencx | https://www.scien.cx/2024/07/23/serving-static-files-and-single-page-applications-on-oat-oatpp/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.