Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flask style Blueprint support #181

Merged
merged 14 commits into from
Aug 5, 2021
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions docs/guides/blueprints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
!!!Warning

This feature is currently only available on the "master" branch.

Crow supports flask style blueprints.<br>
A blueprint is a limited app. It cannot handle networking. But it can handle routes.<br>
Blueprints allow developers to compartmentalize their Crow applications, making them a lot more modular.<br><br>

In order for a blueprint to work, it has to be registered with a Crow app before the app is run. This can be done using `#!cpp app.register_blueprint(blueprint);`.<br><br>

Blueprints let you do the following:<br><br>

### Define Routes
You can define routes in a blueprint, similarly to how `#!cpp CROW_ROUTE(app, "/xyz")` works, you can use `#!cpp CROW_BP_ROUTE(blueprint, "/xyz")` to define a blueprint route.

### Define a Prefix
Blueprints can have a prefix assigned to them. This can be done when creating a new blueprint as in `#!cpp crow::blueprint bp("prefix");`. This prefix will be applied to all routes belonging to the blueprint. truning a route such as `/crow/rocks` into `/prefix/crow/rocks`.

!!!Warning

Unlike routes, blueprint prefixes should contain no slashes.


### Use a custom Static directory
Blueprints let you define a custom static directory (relative to your working directory). This can be done by initializing a blueprint as `#!cpp crow::blueprint bp("prefix", "custom_static");`. This does not have an effect on `#!cpp set_static_file_info()`, it's only for when you want direct access to a file.

!!!note

Currently changing which endpoint the blueprint uses isn't possible, so whatever you've set in `CROW_STATIC_ENDPOINT` (default is "static") will be used. Making your final route `/prefix/static/filename`.


### Use a custom Templates directory
Similar to static directories, You can set a custom templates directory (relative to your working directory). To do this you initialize the blueprint as `#!cpp crow::blueprint bp("prefix", "custom_static", "custom_templates");`. Any routes defined for the blueprint will use that directory when calling `#!cpp crow::mustache::load("filename.html")`.

!!!note

If you want to define a custom templates directory without defining a custom static directory, you can pass the static directory as an empty string. Making your constructor `#!cpp crow::blueprint bp("prefix", "", "custom_templates");`.

### Define a custom Catchall route
You can define a custom catchall route for a blueprint by calling `#!cpp CROW_BP_CATCHALL_ROUTE(blueprint)`. This causes any requests with a URL starting with `/prefix` and no route found to call the blueprint's catchall route. if no catchall route is defined, Crow will default to either the parent blueprint or the app's catchall route.

### Register other Blueprints
Blueprints can also register other blueprints. This is done through `#!cpp blueprint.register_blueprint(blueprint_2);`. The child blueprint's routes become `/prefix/prefix_2/abc/xyz`.
4 changes: 4 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ else ()
target_compile_options(example_json_map PRIVATE "${compiler_options}")
target_link_libraries(example_json_map PUBLIC ${REQUIRED_LIBRARIES})

add_executable(example_blueprint example_blueprint.cpp)
target_compile_options(example_blueprint PRIVATE "${compiler_options}")
target_link_libraries(example_blueprint PUBLIC ${REQUIRED_LIBRARIES})

add_custom_command(OUTPUT example_chat.html
COMMAND ${CMAKE_COMMAND} -E
copy ${PROJECT_SOURCE_DIR}/example_chat.html ${CMAKE_CURRENT_BINARY_DIR}/example_chat.html
Expand Down
35 changes: 35 additions & 0 deletions examples/example_blueprint.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#define CROW_MAIN
#include "crow.h"

int main()
{
crow::SimpleApp app;

crow::Blueprint bp("bp_prefix", "cstat", "ctemplate");


crow::Blueprint sub_bp("bp2", "csstat", "cstemplate");

CROW_BP_ROUTE(sub_bp, "/")
([]() {
return "Hello world!";
});

/* CROW_BP_ROUTE(bp, "/templatt")
([]() {
crow::mustache::context ctxdat;
ctxdat["messg"] = "fifty five!!";

auto page = crow::mustache::load("indks.html");

return page.render(ctxdat);
});
*/
CROW_BP_CATCHALL_ROUTE(sub_bp)([](){return "WRONG!!";});


bp.register_blueprint(sub_bp);
app.register_blueprint(bp);

app.loglevel(crow::LogLevel::DEBUG).port(18080).run();
}
56 changes: 46 additions & 10 deletions include/crow/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@

#ifdef CROW_MSVC_WORKAROUND
#define CROW_ROUTE(app, url) app.route_dynamic(url)
#define CROW_BP_ROUTE(blueprint, url) blueprint.new_rule_dynamic(url)
#else
#define CROW_ROUTE(app, url) app.route<crow::black_magic::get_parameter_tag(url)>(url)
#define CROW_BP_ROUTE(blueprint, url) blueprint.new_rule_tagged<crow::black_magic::get_parameter_tag(url)>(url)
#endif
#define CROW_CATCHALL_ROUTE(app) app.catchall_route()
#define CROW_BP_CATCHALL_ROUTE(blueprint) blueprint.catchall_rule()

namespace crow
{
Expand Down Expand Up @@ -81,6 +84,12 @@ namespace crow
return router_.new_rule_dynamic(std::move(rule));
}

// ///Create a dynamic route for a blueprint using a rule (**Use CROW_BP_ROUTE instead**)
The-EDev marked this conversation as resolved.
Show resolved Hide resolved
// DynamicRule& route_dynamic(Blueprint& blueprint, std::string&& rule)
// {
// return blueprint.new_rule_dynamic(std::move(rule));
// }

///Create a route using a rule (**Use CROW_ROUTE instead**)
template <uint64_t Tag>
auto route(std::string&& rule)
Expand Down Expand Up @@ -159,12 +168,18 @@ namespace crow
/// crow::LogLevel::Warning (2)<br>
/// crow::LogLevel::Error (3)<br>
/// crow::LogLevel::Critical (4)<br>
self_t& loglevel(crow::LogLevel level)
self_t& loglevel(LogLevel level)
{
crow::logger::setLogLevel(level);
return *this;
}

self_t& register_blueprint(Blueprint& blueprint)
{
router_.register_blueprint(blueprint);
return *this;
}

///Set a custom duration and function to run on every tick
template <typename Duration, typename Func>
self_t& tick(Duration d, Func f) {
Expand Down Expand Up @@ -192,7 +207,34 @@ namespace crow
///Go through the rules, upgrade them if possible, and add them to the list of rules
void validate()
{
router_.validate();
if (!validated_)
{

#ifndef CROW_DISABLE_STATIC_DIR
route<crow::black_magic::get_parameter_tag(CROW_STATIC_ENDPOINT)>(CROW_STATIC_ENDPOINT)
([](crow::response& res, std::string file_path_partial)
{
res.set_static_file_info(CROW_STATIC_DIRECTORY + file_path_partial);
res.end();
});

for (auto& bp : router_.blueprints())
{
if (!bp->static_dir().empty())
{
bp->new_rule_tagged<crow::black_magic::get_parameter_tag(CROW_STATIC_ENDPOINT)>(CROW_STATIC_ENDPOINT)
([bp](crow::response& res, std::string file_path_partial)
{
res.set_static_file_info(bp->static_dir() + '/' + file_path_partial);
res.end();
});
}
}
#endif

router_.validate();
validated_ = true;
}
}

///Notify anything using `wait_for_server_start()` to proceed
Expand All @@ -206,14 +248,7 @@ namespace crow
///Run the server
void run()
{
#ifndef CROW_DISABLE_STATIC_DIR
route<crow::black_magic::get_parameter_tag(CROW_STATIC_ENDPOINT)>(CROW_STATIC_ENDPOINT)
([](crow::response& res, std::string file_path_partial)
{
res.set_static_file_info(CROW_STATIC_DIRECTORY + file_path_partial);
res.end();
});
#endif

validate();

#ifdef CROW_ENABLE_SSL
Expand Down Expand Up @@ -361,6 +396,7 @@ namespace crow
private:
uint16_t port_ = 80;
uint16_t concurrency_ = 1;
bool validated_ = false;
std::string server_name_ = std::string("Crow/") + VERSION;
std::string bindaddr_ = "0.0.0.0";
Router router_;
Expand Down
4 changes: 2 additions & 2 deletions include/crow/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace crow
{
enum class HTTPMethod
enum class HTTPMethod : char
{
#ifndef DELETE
DELETE = 0,
Expand Down Expand Up @@ -69,7 +69,7 @@ namespace crow
return "invalid";
}

enum class ParamType
enum class ParamType : char
{
INT,
UINT,
Expand Down
Loading