drogonframework / drogon

Drogon: A C++14/17/20 based HTTP web application framework running on Linux/macOS/Unix/Windows
MIT License
11.63k stars 1.12k forks source link

How does Drogon compare to other C++ frameworks? #760

Open SamuelMarks opened 3 years ago

SamuelMarks commented 3 years ago

For the database layer, I am currently weighing up ODB, Oat++, SOCI, cppdb, and sqlpp11 [if sqlpp adds support for CREATE TABLE]. You here at drogon seem to have your own ORM layer, but with only PostgreSQL and MySQL support I'm a little worried from a testing and server-less perspective (really would be nice to see support for an embedded database like SQLite).

For the REST API layer I haven't started investigating, although do remember actix being dethroned and a C++ framework taking its place (which is how I found myself here!).


I am planning to use LLVM (clang, libclang, libtooling) to synchronise [bidirectionally] OpenAPI with C++ code. I've done the same in Python, and WiP for Rust, Swift, Java, Kotlin, and TypeScript.

With my compiler driven approach, I expect people to be able to rapidly produce REST API + db backends with full test and doc coverage, and be able to immediately translate the interfaces across language boundaries (e.g., to frontends, or to rewrite a slow-performing Python backend in C++ or Rust).

Currently focussing on the non-Turing-complete as aspect of this, translating just the interfaces, tests, docs, defaults, and types.


I am writing tools to allow engineers to develop faster, and with higher quality. Will only target one ORM and one REST API layer for C++, at least in the short-term.

So my question is, and I understand that posting here will provide a heavily biased answer, how do I decide between the various C++ frameworks?

Thanks

an-tao commented 3 years ago

For the database layer, I am currently weighing up ODB, Oat++, SOCI, cppdb, and sqlpp11 [if sqlpp adds support for CREATE TABLE]. You here at drogon seem to have your own ORM layer, but with only PostgreSQL and MySQL support I'm a little worried from a testing and server-less perspective (really would be nice to see support for an embedded database like SQLite).

Sqlite3 has been supported by Drogon. and recently, the Redis is also supported.

For the REST API layer I haven't started investigating, although do remember actix being dethroned and a C++ framework taking its place (which is how I found myself here!).

I am planning to use LLVM (clang, libclang, libtooling) to synchronise [bidirectionally] OpenAPI with C++ code. I've done the same in Python, and WiP for Rust, Swift, Java, Kotlin, and TypeScript.

With my compiler driven approach, I expect people to be able to rapidly produce REST API + db backends with full test and doc coverage, and be able to immediately translate the interfaces across language boundaries (e.g., to frontends, or to rewrite a slow-performing Python backend in C++ or Rust).

Currently focussing on the non-Turing-complete as aspect of this, translating just the interfaces, tests, docs, defaults, and types.

I am writing tools to allow engineers to develop faster, and with higher quality. Will only target one ORM and one REST API layer for C++, at least in the short-term.

This is really a great plan. There are a lot of requirements of Drogon to support Swagger , I'm looking forward to your tool. Does it need some special comments in the C++ code?

So my question is, and I understand that posting here will provide a heavily biased answer, how do I decide between the various C++ frameworks?

Thanks

IMO, performance and rich features are good considerations, I think Drogon is quite competitive in this regards :)

rbugajewski commented 3 years ago

@SamuelMarks As you already guessed, the answers provided here may be heavily biased. This is like asking on an Emacs mailing list if Vim is still the best editor, if you understand what I mean 🙂

I’ll try to be as objective as possible, maybe this can help you decide which framework is the best one for your use case. But be aware that there were subjective decisions why I settled on Drogon. I cannot tell you a lot about the other C++ frameworks in practice, because I don’t use them, but I can tell you what ultimately led to my decision to use Drogon after evaluating these frameworks, the ecosystem around them, and their documentation. I’ll exclude frameworks in other languages that I used for over two decades and assume that you know what you do if you decide on a C++ web framework.

I successfully use Drogon in a couple of production environments (currently still behind a proxy, but this is something for another discussion).

  1. Drogon has a very open development model. Every contribution is welcome, we are pretty open to every PR if it doesn’t affect performance very much (just check this for yourself). In case we decide against integrating something into the main development branch, there is still the possibility to create a plugin from a PR and publish it as a separate project, as Drogon already has a public plugin API. The other projects have a rather more conservative C++ development model, partially development is closed on some Git server, or PRs aren’t as welcome. Personally I’m critical of GitHub in the recent months, but it definitely democratized development and makes it easier to push development forward and create a community around Drogon.
  2. We’re a small and in my opinion pretty friendly community. You’ll usually get help fast either in our official Gitter channel, or in case it is a bug, right here in the issue tracker.
  3. Combined with the more modern development model compared to some older C++ frameworks, Drogon also tries to use modern C++ idioms. We even already integrated features from the yet to be released upcoming C++ version, so development is full steam ahead as far as time of the main contributors allows (@an-tao and @marty1885 are very active in this regard).
  4. I also really like most parts of Drogon’s syntax and prefer it over most of the other C++ frameworks, but this is heavily subjective.
  5. Drogon’s batteries included approach is the perfect one in my opinion. In the C++ world I don’t really see a lot of sense to combine multiple frameworks together to something that is as feature-complete as Drogon. In this case I would probably just go with Boost, and write small layers around the dependencies. YMMV and that’s also the reason why so many different frameworks with different approaches exist.
  6. While Drogon’s documentation is a little bit convoluted in some places (meaning that you would expect it at another place in the docs), it is rather on the complete side, and additionally gives clear examples. It is also easy to make changes or start discussions in case something is unclear. Furthermore we have tests that also show how you can use the framework and launch your new project based on Drogon.
  7. Drogon is fast. While I don’t care about being 🥇, it is good to know that this framework can scale. Even if you don’t need the scale, you can run Drogon on resource-restricted hardware with a pretty decent performance (this is already successfully done).
  8. I use Drogon for web projects and share the same source code with a mobile iOS backend (PostgreSQL on the server, SQLite on the clients). This is of course possible due to C++, but also due to Drogon’s speed. I haven’t ported the backend to Android yet, but there’s at least one person who already successfully runs Drogon on Android devices. This is very versatile in my opinion, and allows code reuse and code sharing (Drogon is also climate-friendly, because it uses less resources for the same tasks 😉)

I also use the LLVM toolchain, there shouldn’t be any issues here.

I hope I can ease your decision and wish you good luck with your project, as it looks pretty interesting!

rbugajewski commented 3 years ago

I forgot to mention the MIT license under which Drogon is released that is very liberal and allows to use the framework for commercial projects. In some projects you aren’t allowed to develop in an open source model where licenses like GPL simply wouldn’t work.

marty1885 commented 3 years ago

I'll try my best to be neutral.

How do I decide between the various C++ frameworks?

For me it's the mix of performance, features and weight. I started using Drogon after I tried a few C++ web frameworks for a commercial HPC project. Oat++ and Wt takes in too much dependency, cpp-httplib lacks in feature and Crow has stopped development. Drogon provides the right mix of features to be useful but not too removed from the underlying technology. And it gives the user enough control to fine tune it's performance. Drogon can be really fast used correctly. Once (in development environment) few bugged clients sent >10000 requests/min for an hour. And Drogon handles it smoothly, 0 requests are dropped.

BTW, we are working on drogon2. The API should be mostly compatible while bringing more modern features. There should be better test coverage, more optimizations, greater coroutine support, cleaner error messages, etc.. (and hopefully I can get HTTP/2 working).

interfector18 commented 3 years ago

I agree with all of the above, in the C++ community, performance can hardly be overstated and any framework worth consideration has to be performant. Thus the conversation shifts to which framework is easier to use, how feature rich is it, how it fits into the current technology ecosystem, does it have an ecosystem of its own and so on.

Going by performance on TFB, choices narrow to either Lithium or Drogon, with Lithium beaing more performant by slim margins except in json serialization. Json library is going to be replaced with a more performant one in drogon2. Next I'll point out that lithium is compiled with PGO, LTO and -march=native while Drogon is not, as can be seen here lithium and here drogon. The performance difference comes down to more aggressive compiler optimizations.

On ease of use and feature richness, I think drogon wins here hands down, outside the core api and registering handlers, as drogon has filters, AOP interface, support for server rendering, and a plugin interface. I've been thinking about writing a plugin that is a dynamic plugin manager, and can at runtime load other plugins. That would enable drogon to be modular after compiling. One drawback I see with Lithium on this front is that while this is also possible with manual implementation, but it doesn't have a de facto standard, resulting in a roadblock for a community ecosystem of plugins to emerge.

Some benchmarks for reference: PGO LTO Also note, they have synergistic effects, and when combined provide awesome results.

SamuelMarks commented 3 years ago

Thanks for your feedback


@an-tao: Great to hear! - Yeah I think I just read past the Postgres and MySQL line (also redis hasn't made the README yet)

In terms of Swagger/OpenAPI, it probably does need some special comments. I always try to get away without, although in this case that would require tracing all possible status codes that could be returned, and all possible outputs (e.g., to match the output to a specific schema, then in the OpenAPI link it to a definitions key in JSON-Schema format).

Which, TBH, would be easier for the programmer if it was all present just under/above the route. Whether in a new C++ syntax, like: https://github.com/oatpp/example-crud/blob/4aff328/src/controller/UserController.hpp#L68-L74 (+ https://github.com/oatpp/example-crud/blob/4aff328/src/SwaggerComponent.hpp)

Or you can take the approach I do in Python, with special comments like: https://github.com/offscale/cdd-python/blob/5aaa940/cdd/routes/emit_constants.py#L9-L29


@rbugajewski: nano > emacs & vim :P

Great, yeah I wouldn't be surprised if I start using it for mobile dev. My initial targets are server and desktop (macOS, Windows), but with the open-source nature of my compiler driven approach, the fewer target limitations the better.

Speed FTW

Yeah, on the license side I release all my stuff under (Apache-2.0 OR MIT), a.k.a., the Rust license. So definitely good to see here. I do try and always avoid LGPL, GPL, and AGPL.


@marty1885: I remember giving a C++ back in 2016 on C++ web frameworks, and talking about Crow, and maybe in 2013 was talking about Wt (really was aiming for users who disabled JavaScript back then, and doing crazy things with PDFs on the C++ side).

On the drogon2 side, for the aforementioned code parsers and code generators, can one assume just drogon2—assuming I pick your framework—should be targeted?


@interfector18: In terms of dynamic plugins, I remember playing around with Kore back in the day with C. It's a good concept, the trick is in guaranteeing no clients are dropped during the reload. Lithium does look good also, their ORM isn't too ugly, and the rest of their syntax is nice also (although I don't know how I feel about no Windows support… I need Windows, maybe if they link me the MSVC bug I can take a look and try and fix / workaround)…


But honestly I was a little surprised about how much feedback I've received in half a day from the community here. Amazing! - That alone probably suffices to choose drogon ^_^

marty1885 commented 3 years ago

I think it will, but with two minor notes. You can count on most APIs to keep working as they are. But drogon2 will be on C++20; mainly to fully utilize coroutine, concepts and reduce the use of SFINAE. Yet clang hasn't move coroutines out of experimental as of clang 12. And we are planing on using a new JSON library due to performance issues (most likely nlohmann/json, boost.json looks attractive). You might want to use GCC for compilation while clang works on coroutines and overload fromRequest to use a non-default JSON parser.

Note of performance: Drogon2 beats lithium without LTO and PGO as of now. I hope it doesn't get slower as we add missing features back.

SamuelMarks commented 3 years ago

@marty1885 I don't mind using trunk versions of compilers, just so long as I can support all the target OSs I care about. Which today is macOS, Windows, and Linux. I also have some unrelated projects targeting SunOS (Solaris -> OpenSolaris -> illumos), BSDs (FreeBSD, NetBSD, OpenBSD), iOS, and Android. So when I get around to unification, then it's important to have support there. But if it's as trivial as switching to gcc, then no qualms from my side.

On a side note I'm looking forward to reflection and executors in C++, hopefully by C++23.

As a different aside, I write in C89 when I target portability, happy to use the latest standard for my C++ projects though…

Impressive that you're now beating lithium. You're making a damn good case for drogon!

SamuelMarks commented 3 years ago

Just took another look. Does drogon not have a CREATE TABLE in C++ code? - A quick search brought up https://github.com/an-tao/drogon/blob/ffda846/orm_lib/tests/db_test.cc#L91-L103 (I'm asking because https://drogon.docsforge.com/master/database-general/database-orm/#model-class-interface)

Orm++ does proper schema migration stuff, and Lithium has an odd but usable syntax for its schema definition with C++.

an-tao commented 3 years ago

Hi, The operating mechanism of ORM is different from what you think, in Drogon, we create model classes via drogon_ctl from existing tables, not the other way around. Please refer to the ORM section for more information.

SamuelMarks commented 3 years ago

@an-tao Yeah I saw that but was a little confused. So you can generate model classes from existing tables, but you can't create new tables from existing model classes? - Is this planned?

an-tao commented 3 years ago

Yes. we will discuss your suggestion about creating tables from model classes, @marty1885 , @rbugajewski , @interfector18 do we need this feature?

rbugajewski commented 3 years ago

This is not needed at all, as the database is our only source of truth and I would like to keep it that way. I don’t see any sense to make classes the source of truth, and if both would be the source of truth we would have conflicts and probably new messy issues.

Database migrations are a little bit unfortunate right now, because you need to keep around two SQL files (setup & teardown) for every database change if you want to have VC-like functionality. I thought about adding a couple of simple commands to drogon_ctl which could perform migrations (create, migrate, rollback etc.), and then some kind of simple interface where you could define migrations in C++ code with the Drogon syntax you already know, but I simply didn’t had the time, yet.

Elwin-zhu commented 3 years ago

@SamuelMarks As you already guessed, the answers provided here may be heavily biased. This is like asking on an Emacs mailing list if Vim is still the best editor, if you understand what I mean slightly_smiling_face

I’ll try to be as objective as possible, maybe this can help you decide which framework is the best one for your use case. But be aware that there were subjective decisions why I settled on Drogon. I cannot tell you a lot about the other C++ frameworks in practice, because I don’t use them, but I can tell you what ultimately led to my decision to use Drogon after evaluating these frameworks, the ecosystem around them, and their documentation. I’ll exclude frameworks in other languages that I used for over two decades and assume that you know what you do if you decide on a C++ web framework.

I successfully use Drogon in a couple of production environments (currently still behind a proxy, but this is something for another discussion).

1. Drogon has a very open development model. Every contribution is welcome, we are pretty open to every PR if it doesn’t affect performance very much (just check this for yourself). In case we decide against integrating something into the main development branch, there is still the possibility to create a plugin from a PR and publish it as a separate project, as Drogon already has a public plugin API. The other projects have a rather more conservative C++ development model, partially development is closed on some Git server, or PRs aren’t as welcome. Personally I’m critical of GitHub in the recent months, but it definitely democratized development and makes it easier to push development forward and create a community around Drogon.

2. We’re a small and in my opinion pretty friendly community. You’ll usually get help fast either in our official Gitter channel, or in case it is a bug, right here in the issue tracker.

3. Combined with the more modern development model compared to some older C++ frameworks, Drogon also tries to use modern C++ idioms. We even already integrated features from the yet to be released upcoming C++ version, so development is full steam ahead as far as time of the main contributors allows (@an-tao and @marty1885 are very active in this regard).

4. I also really like most parts of Drogon’s syntax and prefer it over most of the other C++ frameworks, but this is heavily subjective.

5. Drogon’s batteries included approach is the perfect one in my opinion. In the C++ world I don’t really see a lot of sense to combine multiple frameworks together to something that is as feature-complete as Drogon. In this case I would probably just go with Boost, and write small layers around the dependencies. YMMV and that’s also the reason why so many different frameworks with different approaches exist.

6. While Drogon’s documentation is a little bit convoluted in some places (meaning that you would expect it at another place in the docs), it is rather on the complete side, and additionally gives clear examples. It is also easy to make changes or start discussions in case something is unclear. Furthermore we have tests that also show how you can use the framework and launch your new project based on Drogon.

7. Drogon is fast. While I don’t care about being 1st_place_medal, it is good to know that this framework can scale. Even if you don’t need the scale, you can run Drogon on resource-restricted hardware with a pretty decent performance (this is already successfully done).

8. I use Drogon for web projects and share the same source code with a mobile iOS backend (PostgreSQL on the server, SQLite on the clients). This is of course possible due to C++, but also due to Drogon’s speed. I haven’t ported the backend to Android yet, but there’s at least one person who already successfully runs Drogon on Android devices. This is very versatile in my opinion, and allows code reuse and code sharing (Drogon is also climate-friendly, because it uses less resources for the same tasks wink)

I also use the LLVM toolchain, there shouldn’t be any issues here.

I hope I can ease your decision and wish you good luck with your project, as it looks pretty interesting!

hello sir, you said " there’s at least one person who already successfully runs Drogon on Android devices", can you tell me the right way to run Drogon on Android? using the "Android Studio + Ndk +CMake" or develop a native c++ source code in Android open source project? or other way...?

rbugajewski commented 3 years ago

@Elwin-zhu Yes, going the NDK / JNI route is what I recommend.

Elwin-zhu commented 3 years ago

yes, I based the ndk and compile succuess on trantor, but compile failed on drogon because the uuid lib.

SamuelMarks commented 3 years ago

What error are you getting? - Probably best creating a new issue…

PS: You can probably just macro the UUID lib and use https://android.googlesource.com/platform/development/+/73a5a3b/ndk/platforms/android-20/include/linux/uuid.h directly. Older solutions: https://stackoverflow.com/q/11888055

marty1885 commented 3 years ago

Please open a new issue if you think it is a bug/something the devs needs to address. Commenting below other threads is distracting and makes progress tracking difficult.

Ali-MZ-Basket commented 2 years ago

drogon vs actix https://www.youtube.com/watch?v=3Sn1tedG9zw

nobody93 commented 1 year ago

BTW, we are working on drogon2. The API should be mostly compatible while bringing more modern features. There should be better test coverage, more optimizations, greater coroutine support, cleaner error messages, etc.. (and hopefully I can get HTTP/2 working).

Where is the drogon2 source github, the same in https://github.com/drogonframework/drogon?

marty1885 commented 1 year ago

@nobody93 We ended up backporting most changes drogon2 has back into drogon. Migrating off trantor into ASIO was hard and not worth it.

I'm working on HTTP/2 support right now. You are missing out nothing :) https://github.com/drogonframework/drogon/pull/1554