libzeep
=======

[![DOI](https://zenodo.org/badge/44161414.svg)](https://zenodo.org/badge/latestdoi/44161414)

[![github CI](https://github.com/mhekkel/libzeep/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/mhekkel/libzeep/actions)
[![github CI](https://github.com/mhekkel/libzeep/actions/workflows/build-documentation.yml/badge.svg)](https://github.com/mhekkel/libzeep/actions)

TL;DR
-----

Libzeep is a web application framework written in C++. To see a starter project
visit the [libzeep-webapp-starter](https://github.com/mhekkel/libzeep-webapp-starter.git)
page.

About
-----

Libzeep was originally developed to make it easy to create SOAP servers. And since
working with SOAP means working with XML and no decent C++ XML library
existed on my radar at that time I created a full XML library as well.

Unfortunately (well, considering the work I did), REST proved to be more
popular than SOAP, and so I added a better JSON implementation to version
4 of libzeep as well as a way to create REST servers more easily.

But then I had to use Spring for some time and was impressed by the simplicity
of building interactive web applications and thought I should bring that
simplicity to the C++ world. After all, my applications need raw speed and
no, Java is not fast.

Version 6.0.0 of libzeep was a completely refactored set of libraries. One
for manipulating XML, one for handling JSON and one for building web applications.

But then I decided it would be better to have the xml code in a separate library
and so version 7 now comes without an XML library but uses zeem instead.

What remains is a web application library. This one makes it very easy to build
a HTTP server that serves HTML but also speaks REST and SOAP. The current
implementation consists of a HTTP server class to which you can add controllers.
Each controller has a path prefix and handles requests for some entries in this
uri path. The base class zeep::http::controller can be used as a base class for
a REST controller.

The HTML controller can be used as a base class so you can add methods that
will be called for certain URI paths. In combination with the available tag
processors you can then create and return dynamic XHTML pages.

Full documentation can be found at:

[mhekkel.github.io/libzeep/](https://mhekkel.github.io/libzeep/)

Building libzeep
----------------

To build libzeep you have to have [cmake](https://cmake.org/) installed.

And, unless you are using macOS, it is recommended to install
[mrc](https://github.com/mhekkel/mrc) in order to have resources support in libzeep.

The commands to build libzeep from the command line are e.g.:

```bash
    git clone https://github.com/mhekkel/libzeep
    cd libzeep
    cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
    cmake --build build
    ctest --test-dir build
    cmake --install build
```

Creating a simple web application
---------------------------------

Create a template in xhtml first, store this as `hello.xhtml` in a directory called `docroot`:

```xml
<!DOCTYPE html SYSTEM "about:legacy-compat">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:z="http://www.hekkelman.com/libzeep/m2">
  <head>
    <title>Hello</title>
  </head>
  <p>Hello, <span z:text="${name ?: 'world'}"/>!</p>
</html>
```

Then create a source file called `http-server.cpp` with the following content:

```cpp
#define WEBAPP_USES_RESOURCES 0

#include <zeep/http/server.hpp>
#include <zeep/http/html-controller.hpp>
#include <zeep/http/template-processor.hpp>

class hello_controller : public zeep::http::html_controller
{
  public:
    hello_controller()
    {
        map_get("", &hello_controller::handle_index, "name");
        map_get("index.html", &hello_controller::handle_index, "name");
        map_get("hello/{name}", &hello_controller::handle_index, "name");
    }

    zeep::http::reply handle_index(const zeep::http::scope& scope,
        std::optional<std::string> user)
    {
        zeep::http::scope sub(scope);
        sub.put("name", user.value_or("world"));

        return get_template_processor().create_reply_from_template("hello.xhtml", sub);
    }
};

int main()
{
    zeep::http::server srv(std::filesystem::canonical("docroot"));

    srv.add_controller(new hello_controller());

    srv.bind("::", 8080);
    srv.run(2);

    return 0;
}
```

Create a `CMakeLists.txt` file:

```cmake
cmake_minimum_required(VERSION 3.16)

project(http-server LANGUAGES CXX)

set(CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(zeep REQUIRED)

add_executable(http-server http-server.cpp)
target_link_libraries(http-server zeep::zeep)
```

And configure and build the app:

```bash
cmake .
cmake --build .
```

And then run it:

```bash
./http-server
```

Now you can access the result using the following URL's:

* <http://localhost:8080/>
* <http://localhost:8080/index.html?name=maarten>
* <http://localhost:8080/hello/maarten>
