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

Question about blueprints and static routes #585

Closed
xia-stan opened this issue Jan 17, 2023 · 18 comments
Closed

Question about blueprints and static routes #585

xia-stan opened this issue Jan 17, 2023 · 18 comments

Comments

@xia-stan
Copy link
Contributor

I'm serving my OpenAPI specification using the Swagger UI framework. I've got everything working using the SimpleApp object. I'm reworking the code to use blueprints. I am having trouble with the server not finding files in the expected paths. When using a blueprint with no overrides, I expect to need the following directory structure:

  • server.exe
  • swagger/
    • static/
      • all of the static files associated with the blueprint
  • templates/
    • swagger.html

The endpoint should be http://localhost:18080/swagger/. Logging (see below) shows that we find the template in the right spot (templates/) but it's looking for the static files with the /swagger/ prefix. The documentation notes that the final routes should be <bp prefix>/static/<filename>, which doesn't seem to be working as expected.

I've also reviewed #497. In my case, I just want the default behavior.

Logs

(2023-01-17 20:41:53) [INFO ] Crow/1.0 server is running at http://0.0.0.0:18080 using 16 threads
(2023-01-17 20:41:53) [INFO ] Call app.loglevel(crow::LogLevel::Warning) to hide Info level logs.
(2023-01-17 20:42:09) [INFO ] Request: 127.0.0.1:59614 000001492F43A430 HTTP/1.1 GET /swagger/
(2023-01-17 20:42:09) [INFO ] Response: 000001492F43A430 /swagger/ 200 0
(2023-01-17 20:42:09) [INFO ] Request: 127.0.0.1:59614 000001492F43A430 HTTP/1.1 GET /swagger/swagger-ui.css
(2023-01-17 20:42:09) [INFO ] Response: 000001492F43A430 /swagger/swagger-ui.css 404 0
(2023-01-17 20:42:09) [INFO ] Request: 127.0.0.1:59614 000001492F43A430 HTTP/1.1 GET /swagger/static/swagger.css
(2023-01-17 20:42:09) [INFO ] Response: 000001492F43A430 /swagger/static/swagger.css 404 0

Code

C++ Source

#include <crow_all.h>

int main(int argc, char **argv) {
    crow::SimpleApp app;
    crow::Blueprint bp("swagger");
    app.register_blueprint(bp);
    CROW_BP_ROUTE(bp, "/")
    ([]() {
        auto page = crow::mustache::load("swagger.html");
        return page.render();
    });
    app.port(18080).multithreaded().run();
}

swagger.html

<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Swagger UI</title>
    <link rel="stylesheet" type="text/css" href="static/swagger-ui.css" />
    <link rel="stylesheet" type="text/css" href="static/swagger.css" />
    <link rel="icon" type="image/png" href="static/favicon-32x32.png" sizes="32x32" />
    <link rel="icon" type="image/png" href="static/favicon-16x16.png" sizes="16x16" />
  </head>

  <body>
    <div id="swagger-ui"></div>
    <script src="static/swagger-ui-bundle.js" charset="UTF-8"> </script>
    <script src="static/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
    <script src="static/swagger-initializer.js" charset="UTF-8"> </script>
  </body>
</html>

Software / System

  • Windows 11 Pro 22H2
  • Crow v1.0+5 Security Patch (crow_all.h)
  • MSVC 19.29.30146.0
@mrozigor
Copy link
Member

Hello. First question - have you tried to run this on master? There are a few differences between latest release and master, so it should be a good start ;)

@xia-stan
Copy link
Contributor Author

@mrozigor : I haven't tried master yet. I need to use crow_all.h, and didn't see one readily available in the directory structure. Is that file generated via CMake?

@xia-stan
Copy link
Contributor Author

I found it in CMake. Trying to deal with the ASIO dependency. Is that necessary for building crow_all.h? Looks like it's only part of the link libraries.

@mrozigor
Copy link
Member

You can use script from scripts dir -> merge_all.py. Example: python3 scripts/merge_all.py include crow_all.h

@xia-stan
Copy link
Contributor Author

Just did that. Got Cmake working, but Windows doesn't like the wildcard expansion.

@mrozigor
Copy link
Member

So you generated file properly, but another problem occurred?

@xia-stan
Copy link
Contributor Author

xia-stan commented Jan 19, 2023

Got crow_all.h built from HEAD, and I get an error with asio.hpp not being found. It gets included but not actually pulled into the header. It seems similar to how boost is handled. Does the header-only implementation work without asio?

I already had to add the 37 boost dependencies as submodules. I can add asio to the list. What version of asio should I reference my submodule to?

@mrozigor
Copy link
Member

You can use Findasio.cmake from cmake dir. Or just manually include/link latest version.

@xia-stan
Copy link
Contributor Author

I know I don't have it installed globally, that's why CMake was balking. Looking at their website it turns out that asio is already included in boost. Crow already depends on the boost/asio header. I updated the namespaces to boost::asio and include paths, boost/asio.hpp. I'm now getting compilation errors. Here's a snippit of them:
image

I'll try the non-boost version of asio now. What's interesting is that some of the errors detail::task_timer doesn't seem to belong to either version of asio's namespace.

@xia-stan
Copy link
Contributor Author

Here's the latest setup. I've

I'm still seeing the same behavior as before. The Blueprint is prepending swagger to all the URLs before trying to serve them. This finds the HTML template properly, but fails to find the static files. I've kept the Static paths default:
image

Based on this information, I've tried putting the static files in

  • static/
  • static/swagger/
  • swagger/
  • swagger/static/

They always return 404s. I've once again confirmed that the following code works (with templates and static files in the default directories):

#include <crow_all.h>

int main(int argc, char **argv) {
    crow::SimpleApp app;
    CROW_ROUTE(app, "/")([]() { return "Hello world"; });
    CROW_ROUTE(app, "/swagger-ui") ([]() {
        auto page = crow::mustache::load("swagger.html");
        return page.render();
    });
    app.port(18080).multithreaded().run();
}

@mrozigor
Copy link
Member

As I understand correctly HTML loads properly and static files not? Have you tried to change src/href attributes to swagger/static/swagger-ui-bundle.js? Or only swagger-ui-bundle.js?

@xia-stan
Copy link
Contributor Author

xia-stan commented Feb 1, 2023

That's correct. I've attempted changing the static paths to match but the blueprint prefix gets added to any route within the context.
image


I have managed to get this working, but I needed to explicitly define the static and template paths in the blueprint constructor. Here's the amended code:

#include <crow_all.h>

int main(int argc, char **argv) {
    crow::SimpleApp app;
    CROW_ROUTE(app, "/")([]() { return "Hello world"; });
    CROW_ROUTE(app, "/swagger", "swagger/static", "swagger/templates") ([]() {
        auto page = crow::mustache::load("swagger.html");
        return page.render();
    });
    app.port(18080).multithreaded().run();
}

Then defining the src refs to static/swagger-ui-bundle.js work as expected. With the pathing on disk looking like

  • swagger/
    • static
      • swagger-ui-bundle.js
    • templates
      • swagger.html

I'm trying to organize my blueprints. I've moved the blueprint definition to a separate function, and return that blueprint to main. I've kept the pathing identical. Again, it finds the HTML without issue but issues 404s for all of the static elements.
image
This seems like it should be doing the same thing as before. I'm wondering if there's some sort of scoping going on in the lambda or class that's causing it to lose context for the static assets?

#include <crow_all.h>

crow::Blueprint swagger_bp() {
    crow::Blueprint bp("swagger", "swagger/static", "swagger/templates");
    CROW_BP_ROUTE(bp, "/")
    ([]() {
        auto page = crow::mustache::load("swagger.html");
        return page.render();
    });
    return bp;
}

int main(int argc, char **argv) {
    crow::SimpleApp app;
    CROW_ROUTE(app, "/")([]() { return "Hello world"; });
    auto bp = swagger_bp();
    app.register_blueprint(bp);
    app.port(18080).multithreaded().run();
}

@mrozigor
Copy link
Member

mrozigor commented Feb 1, 2023

I haven't implemented blueprints, so I'd have to check in code. Maybe @The-EDev could help here?

@xia-stan
Copy link
Contributor Author

xia-stan commented Feb 1, 2023

Inspecting the previous example with the returned Blueprint object shows that we're missing the static or template paths.
image
I tracked this down to the implemented assignment operator:
image
As you can see, it's missing the assignments for the prefix and template. Adding those fixes this specific issue. Adding the blueprints_ and mw_indices_ variables removes a bad allocation error that happens when passing the SimpleApp object to the function and doing the assignment there.
This also explains an issue I was seeing when returning nested blueprints from functions (i.e. segfaults when registering children). The assignments were never happening properly.

The proposed fix

image

If this fix looks good, I'll be happy to put in a PR to fix it.

@mrozigor
Copy link
Member

mrozigor commented Feb 1, 2023

Great job! I would be great if you prepare PR ;) Thanks.

xia-stan added a commit to xia-stan/Crow that referenced this issue Feb 1, 2023
Adds static_dir_, templates_dir_, blueprints_, and mw_indices_ to the assignment.
This ensures that the Blueprint is assigned all the information.
mrozigor added a commit that referenced this issue Feb 3, 2023
#585 : Resolves issue with blueprint assignments.
@xia-stan xia-stan closed this as completed Feb 3, 2023
@julianxhokaxhiu
Copy link

Sorry to hijack this issue but I have a question related to Crow and Swagger: may I ask how did you implement/integrate the OpenAPI spec with Crow? is there some kind of automatic provider or has to be done by hand? If you could post a simple tutorial I'd appreciate. Thank you in advance!

@drizzle042
Copy link

Hi @xia-stan I know this might be unrelated but I gotta say thank you for this. Your code you shared here contains more info about blueprints than the web docs. I could get up and running easily with it. Again thank you.

@xia-stan
Copy link
Contributor Author

As a note for those who might come later. It's more efficient to create the blueprint in main, and then pass by reference to the generator. This will reduce the number of copies being made.

#include <crow_all.h>

void swagger_blueprint(crow::Blueprint& bp) {
    CROW_BP_ROUTE(bp, "/")
    ([]() {
        auto page = crow::mustache::load("swagger.html");
        return page.render();
    });
}

int main(int argc, char** argv) {
    crow::SimpleApp app;
    CROW_ROUTE(app, "/")([]() { return "Hello world"; });
    crow::Blueprint swag_bp("swagger", "swagger/static", "swagger/templates");
    swagger_blueprint(swag_bp);
    app.register_blueprint(swag_bp);
    app.port(18080).multithreaded().run();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants