drogon README

The project's README from github.com/drogonframework/drogon. As one markdown file: README.md.

Build Status Conan Center Join the telegram group at https://t.me/joinchat/_mMNGv0748ZkMDAx Join our Discord Docker image

English | 简体中文 | 繁體中文

Overview

Drogon is a C++17/20 based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. Drogon is the name of a dragon from the American TV series Game of Thrones, which I really enjoy.

Drogon is a cross-platform framework, It supports Linux, macOS, FreeBSD, OpenBSD, HaikuOS, and Windows. Its main features are as follows:

A very simple example

Unlike most C++ frameworks, the main program of the drogon application can be kept clean and simple. Drogon uses a few tricks to decouple controllers from the main program. The routing settings of controllers can be done through macros or configuration file.

Below is the main program of a typical drogon application:

#include <drogon/drogon.h>

using namespace drogon;

int main()
{
    app().setLogPath("./")
         .setLogLevel(trantor::Logger::kWarn)
         .addListener("0.0.0.0", 80)
         .setThreadNum(16)
         .enableRunAsDaemon()
         .run();
}

It can be further simplified by using configuration file as follows:

#include <drogon/drogon.h>

using namespace drogon;

int main()
{
    app().loadConfigFile("./config.json").run();
}

Drogon provides some interfaces for adding controller logic directly in the main() function, for example, user can register a handler like this in Drogon:

app().registerHandler("/test?username={name}",
                    [](const HttpRequestPtr& req,
                       std::function<void (const HttpResponsePtr &)> &&callback,
                       const std::string &name) -> void
                    {
                        Json::Value json;
                        json["result"] = "ok";
                        json["message"] = "hello, " + name;
                        HttpResponsePtr resp = HttpResponse::newHttpJsonResponse(json);
                        callback(resp);
                    },
                    {Get,"LoginFilter"});

While such interfaces look intuitive, they are not suitable for complex business logic scenarios. Assuming there are tens or even hundreds of handlers that need to be registered in the framework, isn't it a better practice to implement them separately in their respective classes? So unless your logic is very simple, we don't recommend using above interfaces. Instead, we can create an HttpSimpleController as follows:

/// The TestCtrl.h file
#pragma once
#include <drogon/HttpSimpleController.h>

using namespace drogon;

class TestCtrl : public HttpSimpleController<TestCtrl>
{
public:
    void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
    PATH_LIST_BEGIN
    PATH_ADD("/test",Get);
    PATH_LIST_END
};

/// The TestCtrl.cc file
#include "TestCtrl.h"

void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
                                      std::function<void (const HttpResponsePtr &)> &&callback)
{
    // write your application logic here
    HttpResponsePtr resp = HttpResponse::newHttpResponse();
    resp->setBody("<p>Hello, world!</p>");
    resp->setExpiredTime(0);
    callback(resp);
}

Most of the above programs can be automatically generated by the command line tool drogon_ctl provided by drogon (The command is drogon_ctl create controller TestCtrl). All the user needs to do is add their own business logic. In the example, the controller returns a Hello, world! string when the client accesses the http://ip/test URL.

For JSON format response, we create the controller as follows:

/// The header file
#pragma once

#include <drogon/HttpSimpleController.h>

using namespace drogon;

class JsonCtrl : public HttpSimpleController<JsonCtrl>
{
  public:
    void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
    PATH_LIST_BEGIN
    // list path definitions here;
    PATH_ADD("/json", Get);
    PATH_LIST_END
};

/// The source file
#include "JsonCtrl.h"

void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req,
                                      std::function<void(const HttpResponsePtr &)> &&callback)
{
    Json::Value ret;
    ret["message"] = "Hello, World!";
    HttpResponsePtr resp = HttpResponse::newHttpJsonResponse(ret);
    callback(resp);
}

Let's go a step further and create a demo RESTful API with the HttpController class, as shown below (Omit the source file):

/// The header file
#pragma once
#include <drogon/HttpController.h>

using namespace drogon;

namespace api::v1
{
class User : public HttpController<User>
{
  public:
    METHOD_LIST_BEGIN
    // use METHOD_ADD to add your custom processing function here;
    METHOD_ADD(User::getInfo, "/{id}", Get); // path is /api/v1/User/{arg1}
    METHOD_ADD(User::getDetailInfo, "/{id}/detailinfo", Get); // path is /api/v1/User/{arg1}/detailinfo
    METHOD_ADD(User::newUser, "/{name}", Post); // path is /api/v1/User/{arg1}
    METHOD_LIST_END
    // your declaration of processing function maybe like this:
    void getInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
    void getDetailInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
    void newUser(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string &&userName);
  public:
    User()
    {
        LOG_DEBUG << "User constructor!";
    }
};
} // namespace api::v1

As you can see, users can use the HttpController to map paths and parameters at the same time. This is a very convenient way to create a RESTful API application.

In addition, you can also find that all handler interfaces are in asynchronous mode, where the response is returned by a callback object. This design is for performance reasons because in asynchronous mode the drogon application can handle a large number of concurrent requests with a small number of threads.

After compiling all of the above source files, we get a very simple web application. This is a good start. For more information, please visit the documentation on GitHub.

Cross-compilation

Drogon supports cross-compilation, you should define the CMAKE_SYSTEM_NAME in toolchain file, for example:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

You can disable building options for examples and drogon_ctl by settings BUILD_EXAMPLES and BUILD_CTL to OFF in the toolchain file.

Building options

Drogon provides some building options, you can enable or disable them by setting the corresponding variables to ON or OFF in the cmake command line, cmake file etc...

Option name Description Default value
BUILD_CTL Build drogon_ctl ON
BUILD_EXAMPLES Build examples ON
BUILD_ORM Build orm ON
COZ_PROFILING Use coz for profiling OFF
BUILD_SHARED_LIBS Build drogon as a shared lib OFF
BUILD_DOC Build Doxygen documentation OFF
BUILD_BROTLI Build Brotli ON
BUILD_YAML_CONFIG Build yaml config ON
USE_SUBMODULE Use trantor as a submodule ON

Contributions

This project exists thanks to all the people who contribute code.

Code contributors

Every contribution is welcome. Please refer to the contribution guidelines for more information.

drogon (drogonframework/drogon)

Searching Database…

14.3K ·GitHub
这是什么?Drogon 是一个开源(MIT 许可证)的 C++14/17/20 HTTP 应用框架,用 C++ 编写 Web 应用服务器程序——从 REST API 到服务端渲染的网站和 WebSocket 应用都可以。
它是让我在上面搭建整个应用的完整框架,还是更像一个库?它是一个完整的 Web 应用框架,而不是一个轻量库:包括非阻塞的 HTTP 服务器和客户端、路由、会话、CSP 模板视图、ORM、异步数据库和 Redis 客户端、插件,还有 drogonctl 命令行工具。
我怎么让第一个应用跑起来?先用 drogonctl 命令行工具生成代码('drogonctl create controller TestCtrl'),再写上你的业务逻辑,然后用 CMake 编译。控制器通过宏或配置文件映射到路由,让 main() 保持整洁。
构建之前我需要装好哪些东西?需要一套 C++ 工具链和 CMake:它是从源码构建的,通过 CMake 选项来开关功能(ORM、Brotli、YAML 配置、drogonctl)。trantor 网络库默认作为子模块附带,HTTPS 则需要 OpenSSL。
我把所有处理代码都写在 main() 里没问题吧,还是有什么讲究?在 main() 里直接内联注册处理器只建议用于非常简单的逻辑——README 建议真正的应用改用独立的控制器类。
它主要是给 REST API 用的,还是也能做服务端渲染的页面?各类 Web 后端都行:JSON 请求/响应支持对 RESTful API 开发非常友好,CSP 模板视图覆盖服务端渲染的 HTML,另外 WebSocket、文件上传/下载、gzip/brotli 压缩和请求流水线都是内置的。
它能在哪些操作系统上运行?Linux、macOS、FreeBSD、OpenBSD、HaikuOS 和 Windows 都可以,包括 ARM 架构,还能通过 CMake toolchain 文件进行交叉编译。网络 I/O 用的是 epoll(macOS/FreeBSD 上是 kqueue),高并发性能很好。
处理器必须写成回调风格的吗,还是也支持现代 C++ 的写法?经典处理器通过回调返回响应——这种异步设计让少量线程就能服务大量并发请求。同时也支持 C++ 协程,作为更现代的写法。
它能连哪些数据库?PostgreSQL 和 MySQL/MariaDB 通过非阻塞的异步客户端访问,sqlite3 通过线程池异步访问,另外还支持 Redis——都可以通过一个轻量级 ORM 使用,支持对象与数据库之间的双向映射。
有没有类似中间件的东西,用来处理登录校验这类通用逻辑?有——过滤器链会在请求到达处理器之前执行统一的逻辑(登录验证、HTTP 方法限制),插件在启动时从配置文件加载,还支持带内置 joinpoint 的 AOP。
它为什么叫 Drogon?名字来自电视剧《权力的游戏》里的那条龙,作者说自己非常喜欢这部剧。
What are similar projects?Perfect, carno.js, webserver, cpp-httplib, aiohttp, sails, go-zero, echo
Size
6.5 MB
Stars
14.3K
Age
8y
Commits · 90 Days