SNode.C
Loading...
Searching...
No Matches
express_compat_server.cpp File Reference
#include "core/SNodeC.h"
#include "express/legacy/in/WebApp.h"
#include "log/Logger.h"
#include <nlohmann/json.hpp>
Include dependency graph for express_compat_server.cpp:

Go to the source code of this file.

Classes

class  Router

Typedefs

using Trace = std::vector<json>

Functions

static json snapshot (const std::shared_ptr< express::Request > &req, const std::string &label)
static void ensureTrace (const std::shared_ptr< express::Request > &req)
static void tracePush (const std::shared_ptr< express::Request > &req, const std::string &label)
static json traceGet (const std::shared_ptr< express::Request > &req)
int main (int argc, char *argv[])

Typedef Documentation

◆ Trace

typedef std::vector< json > Trace = std::vector<json>

Definition at line 18 of file express_compat_server.cpp.

Function Documentation

◆ ensureTrace()

void ensureTrace ( const std::shared_ptr< express::Request > & req)
static

Definition at line 48 of file express_compat_server.cpp.

48 {
49 // Create the trace attribute if it doesn't exist yet.
50 req->setAttribute<Trace>(Trace{}, "trace");
51}
constexpr bool setAttribute(const Attribute &attribute, const std::string &subKey="", bool overwrite=false)
std::vector< json > Trace

References utils::MultibleAttributeInjector::setAttribute().

Referenced by tracePush().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int argc,
char * argv[] )

Definition at line 74 of file express_compat_server.cpp.

74 {
75 core::SNodeC::init(argc, argv);
76
77 const express::legacy::in::WebApp app("express-compat");
78
79 // Meta
80 app.get("/__meta", [] APPLICATION(req, res) {
81 res->json({{"ok", true}, {"server", "snodec"}, {"express", true}});
82 });
83
84 // Basic
85 app.get("/health", [] APPLICATION(req, res) {
86 res->json({{"ok", true}, {"label", "health"}});
87 });
88
89 // Case-insensitive routing demo
90 app.get("/Case/Path", [] APPLICATION(req, res) {
91 res->json(snapshot(req, "case"));
92 });
93
94 // Trailing slash demo (strictRouting off => matches both)
95 app.get("/trail/", [] APPLICATION(req, res) {
96 res->json(snapshot(req, "trail"));
97 });
98
99 // Wildcards
100 app.get("/file/*", [] APPLICATION(req, res) {
101 res->json(snapshot(req, "file"));
102 });
103 app.get("/a/*/b/*", [] APPLICATION(req, res) {
104 res->json(snapshot(req, "multi_wild"));
105 });
106
107 // Param decoding
108 app.get("/p/:x", [] APPLICATION(req, res) {
109 res->json(snapshot(req, "param"));
110 });
111
112 // Query decoding/casing
113 app.get("/query/echo", [] APPLICATION(req, res) {
114 res->json(snapshot(req, "query_echo"));
115 });
116
117 // HEAD -> GET fallback (handled by dispatcher/response code)
118 app.get("/head-demo", [] APPLICATION(req, res) {
119 res->set("X-Demo", "1");
120 res->send("head body");
121 });
122
123 // next('route') demo
124 app.get(
125 "/nr/:id(\\d+)",
126 [] MIDDLEWARE(req, res, next) {
127 if (req->params["id"] == "0") {
128 next("route");
129 return;
130 }
131 next();
132 },
133 [] APPLICATION(req, res) {
134 res->json(snapshot(req, "nr_primary"));
135 });
136 app.get("/nr/:id(\\d+)", [] APPLICATION(req, res) {
137 res->json(snapshot(req, "nr_fallback"));
138 });
139
140 // next('router') demo
141 const Router guarded;
142 guarded.use([] MIDDLEWARE(req, res, next) {
143 if (req->queries["allow"] != "true") {
144 next("router");
145 return;
146 }
147 next();
148 });
149 guarded.get("/stats", [] APPLICATION(req, res) {
150 res->json(snapshot(req, "guarded_stats"));
151 });
152 app.use("/guarded", guarded);
153
154 // Fallback when router skipped
155 app.get("/guarded/:rest(.*)", [] APPLICATION(req, res) {
156 res->status(403).json({{"label", "guarded_fallback"}, {"status", 403}});
157 });
158
159 // Root-mounted router (baseUrl should be empty string)
160 const Router root;
161 root.get("/root/test", [] APPLICATION(req, res) {
162 res->json(snapshot(req, "root_mount"));
163 });
164 app.use("/", root);
165
166 // Nested routers trace: req.url / baseUrl stripping
167 const Router api;
168 api.use([] MIDDLEWARE(req, res, next) {
169 tracePush(req, "api.use");
170 next();
171 });
172
173 const Router v1;
174 v1.use([] MIDDLEWARE(req, res, next) {
175 tracePush(req, "v1.use");
176 next();
177 });
178 v1.get("/users/:id", [] APPLICATION(req, res) {
179 tracePush(req, "handler");
180 res->json({{"label", "nested_trace"}, {"trace", traceGet(req)}});
181 });
182
183 api.use("/v1", v1);
184 app.use("/api", api);
185
186 // mergeParams demo (requires your mergeParams patch-set)
187 const Router mpMerge;
188 mpMerge.setMergeParams(true);
189 mpMerge.get("/users/:id", [] APPLICATION(req, res) {
190 res->json(snapshot(req, "mp_merge"));
191 });
192 app.use("/mp/merge/t/:tenant", mpMerge);
193
194 const Router mpNoMerge;
195 mpNoMerge.get("/users/:id", [] APPLICATION(req, res) {
196 res->json(snapshot(req, "mp_nomerge"));
197 });
198 app.use("/mp/nomerge/t/:tenant", mpNoMerge);
199
200 // Params scoping trace: merge vs no-merge
201 auto makeScope = [](bool merge) {
202 const Router parent;
203 parent.setMergeParams();
204 parent.use([merge](auto const& req, auto const&, auto& next) {
205 tracePush(req, merge ? "scopeMerge.parent" : "scopeNoMerge.parent");
206 next();
207 });
208
209 const Router child;
210 child.setMergeParams(merge);
211 child.use([merge](auto const& req, auto const&, auto& next) {
212 tracePush(req, merge ? "scopeMerge.child" : "scopeNoMerge.child");
213 next();
214 });
215 child.get("/end", [merge](auto const& req, auto const& res) {
216 tracePush(req, merge ? "scopeMerge.handler" : "scopeNoMerge.handler");
217 res->json({{"label", merge ? "scope_merge" : "scope_nomerge"}, {"trace", traceGet(req)}});
218 });
219
220 parent.use("/b/:b", child);
221 return parent;
222 };
223
224 app.use("/scope/nomerge/:a", makeScope(false));
225 app.use("/scope/merge/:a", makeScope(true));
226
227 // Param decoding (valid)
228 app.get("/decode/:p", [] APPLICATION(req, res) {
229 res->json(snapshot(req, "decode_ok"));
230 });
231
232 // 404 (GET only, enough for this suite)
233 app.get("/:rest(.*)", [] APPLICATION(req, res) {
234 res->status(404).json({{"label", "not_found"}, {"path", req->path}});
235 });
236
237 app.listen(8080, [](const express::legacy::in::WebApp::SocketAddress& socketAddress, const core::socket::State& state) {
238 switch (state) {
240 VLOG(1) << "express-compat listening on '" << socketAddress.toString() << "'";
241 break;
243 VLOG(1) << "express-compat disabled";
244 break;
246 LOG(ERROR) << "express-compat " << socketAddress.toString() << ": " << state.what();
247 break;
249 LOG(FATAL) << "express-compat " << socketAddress.toString() << ": " << state.what();
250 break;
251 }
252 });
253
254 return core::SNodeC::start();
255}
#define LOG(level)
Definition Logger.h:148
#define VLOG(level)
Definition Logger.h:164
#define APPLICATION(req, res)
Definition Router.h:68
#define MIDDLEWARE(req, res, next)
Definition Router.h:63
static void init(int argc, char *argv[])
Definition SNodeC.cpp:54
static int start(const utils::Timeval &timeOut={LONG_MAX, 0})
Definition SNodeC.cpp:60
static constexpr int DISABLED
Definition State.h:56
static constexpr int ERROR
Definition State.h:57
std::string what() const
Definition State.cpp:114
static constexpr int FATAL
Definition State.h:58
static constexpr int OK
Definition State.h:55
Route & use(const std::function< void(const std::shared_ptr< Request > &, const std::shared_ptr< Response > &)> &lambda) const
Definition Route.cpp:102
Route & get(const std::function< void(const std::shared_ptr< Request > &, const std::shared_ptr< Response > &)> &lambda) const
Definition Route.cpp:104
Route & use(const Router &router) const
Definition Router.cpp:100
Route & get(const Router &router) const
Definition Router.cpp:102
const Router & setMergeParams(bool mergeParams=true) const
Definition Router.cpp:90
typename Server::SocketAddress SocketAddress
Definition WebAppT.h:68
static void tracePush(const std::shared_ptr< express::Request > &req, const std::string &label)
static json snapshot(const std::shared_ptr< express::Request > &req, const std::string &label)
static json traceGet(const std::shared_ptr< express::Request > &req)
WebAppT< web::http::legacy::in::Server > WebApp
Definition WebApp.h:56

References core::socket::State::DISABLED, core::socket::State::ERROR, logger::ERROR, core::socket::State::FATAL, logger::FATAL, express::Router::get(), core::SNodeC::init(), express::Response::json(), net::in::stream::SocketServer< SocketAcceptorT, ConfigSocketServerT, SocketContextFactoryT, Args >::listen(), logger::LogMessage::LogMessage(), core::socket::State::OK, express::Next::operator()(), express::Request::params, express::Request::path, express::Response::send(), express::Response::set(), express::Router::setMergeParams(), snapshot(), core::SNodeC::start(), express::Response::status(), net::in::SocketAddress::toString(), traceGet(), tracePush(), express::WebAppT< ServerT >::WebAppT(), and core::socket::State::what().

Here is the call graph for this function:

◆ snapshot()

json snapshot ( const std::shared_ptr< express::Request > & req,
const std::string & label )
static

Definition at line 20 of file express_compat_server.cpp.

20 {
21 json out = json::object();
22 out["label"] = label;
23 out["method"] = req->method;
24 out["url"] = req->url;
25 out["originalUrl"] = req->originalUrl;
26 out["baseUrl"] = req->baseUrl;
27 out["path"] = req->path;
28
29 json params = json::object();
30 for (const auto& [k, v] : req->params) {
31 params[k] = v;
32 }
33 out["params"] = params;
34
35 json query = json::object();
36 for (const auto& [k, v] : req->queries) {
37 query[k] = v;
38 }
39 out["query"] = query;
40
41 json headers = json::object();
42 headers["x-test"] = req->get("X-Test");
43 out["headers"] = headers;
44
45 return out;
46}
std::string originalUrl
Definition Request.h:77
std::string url
Definition Request.h:98
std::map< std::string, std::string > params
Definition Request.h:81
const std::string & get(const std::string &key, int i=0) const
Definition Request.cpp:95
std::string method
Definition Request.h:97
std::string baseUrl
Definition Request.h:76
std::map< std::string, std::string > queries
Definition Request.h:103
std::string path
Definition Request.h:79

References express::Request::baseUrl, express::Request::get(), express::Request::method, express::Request::originalUrl, express::Request::params, express::Request::path, express::Request::queries, and express::Request::url.

Referenced by main(), and tracePush().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ traceGet()

json traceGet ( const std::shared_ptr< express::Request > & req)
static

Definition at line 62 of file express_compat_server.cpp.

62 {
63 json arr = json::array();
64 req->getAttribute<Trace>(
65 [&](const Trace& t) {
66 for (auto const& e : t) {
67 arr.push_back(e);
68 }
69 },
70 "trace");
71 return arr;
72}
bool getAttribute(const std::function< void(Attribute &)> &onFound, const std::string &subKey="") const

References utils::MultibleAttributeInjector::getAttribute().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ tracePush()

void tracePush ( const std::shared_ptr< express::Request > & req,
const std::string & label )
static

Definition at line 53 of file express_compat_server.cpp.

53 {
54 ensureTrace(req);
55 req->getAttribute<Trace>(
56 [&](Trace& t) {
57 t.emplace_back(snapshot(req, label));
58 },
59 "trace");
60}
static void ensureTrace(const std::shared_ptr< express::Request > &req)

References ensureTrace(), utils::MultibleAttributeInjector::getAttribute(), and snapshot().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function: