Node++ is an asynchronous HTTP(S) engine and framework for low-latency C/C++ web applications / RESTful APIs.
Node++ is an asynchronous HTTP(S) engine and backend framework for low-latency C/C++ web applications and RESTful APIs.
It’s more than twice as fast as Spring Boot and five times faster than Node.js.
C++ backend can render pages in microseconds, even with a database, when used with our efficient DAO/ORM class (see live demo).
It can act as:
Node++ library (paired with OpenSSL and optionally MySQL) contains everything that is necessary to build a complete, production-grade solution, including session management, users accounts, REST calls and multi-language support.
There is a RESTful API generator to generate almost the whole backend code in a few clicks, requiring only an SQL table definition.
The backend framework means that there are 7 server-side events you can react to:
Event | Function called |
---|---|
application start | npp_app_init() |
HTTP request | npp_app_main() |
session start | npp_app_session_init() |
session authentication (login) | npp_app_user_login() |
session logout | npp_app_user_logout() |
session stop | npp_app_session_done() |
application stop | npp_app_done() |
npp_app.cpp has to contain these definitions (even if empty).
As Node++ is single-threaded, the application code does not need to be thread-safe. Horizontal scaling is done through adding processes, not threads.
The whole user session and sessid cookie management is handled by the engine.
By default sessions are not started. To change this add one line to npp_app.h.
Node++'s efficiency makes single CPU, 1 GB AWS EC2 t2.micro free instance sufficient to host a fully-fledged web application with a database for thousands of users.
On a typical server it handles 50,000 requests per second.
Low latency gets Node++ applications “Faster than 100% of tested sites” badge from Pingdom or – as they now don’t publish the percentage – it shows the complete page load in 67 ms:
Why is Node++ faster than other engines?
Node++ has built-in (and enabled by default) protection against most popular attacks, including BEAST, SQL-injection, XSS, and password and cookie brute-force. It does not directly expose the filesystem nor allows any scripting. Its random string generator is FIPS-compliant. CSRF protection is as easy as adding 3 lines to the code.
Default SSL settings give A+ result:
If resource
is a file present in res
or resmin
(i.e. an image or css), it will be served and npp_app_main()
will not be called.
Return static file if present, otherwise “Hello World!”.
void npp_app_main()
{
OUT("Hello World!");
}
Application, yet without moving parts.
void npp_app_main()
{
if ( REQ("") ) // landing page
{
OUT_HTML_HEADER;
OUT("<h1>%s</h1>", NPP_APP_NAME);
OUT("<h2>Welcome to my web app!</h2>");
OUT("<p><a href=\"/about\">About</a></p>");
OUT_HTML_FOOTER;
}
else if ( REQ("about") )
{
OUT_HTML_HEADER;
OUT("<h1>%s</h1>", NPP_APP_NAME);
OUT("<h2>About</h2>");
OUT("<p>Hello World Sample Node++ Web Application</p>");
OUT("<p><a href=\"/\">Back to landing page</a></p>");
OUT_HTML_FOOTER;
}
else // page not found
{
RES_STATUS(404);
}
}
This is a simple 2-pages application demonstrating QS() macro usage to get a value provided by client in the query string.
QS
works with all popular HTTP methods and payload types.
void npp_app_main()
{
if ( REQ("") ) // landing page
{
OUT_HTML_HEADER; // generic HTML header with opening body tag
OUT("<h1>%s</h1>", NPP_APP_NAME);
OUT("<h2>Welcome to my web app!</h2>");
/* show client type */
if ( REQ_DSK )
OUT("<p>You're on desktop, right?</p>");
else if ( REQ_TAB )
OUT("<p>You're on tablet, right?</p>");
else /* REQ_MOB */
OUT("<p>You're on the phone, right?</p>");
/* link to welcome */
OUT("<p>Click <a href=\"/welcome\">here</a> to try my welcoming bot.</p>");
OUT_HTML_FOOTER; // body and html closing tags
}
else if ( REQ("welcome") ) // welcoming bot
{
OUT_HTML_HEADER;
OUT("<h1>%s</h1>", NPP_APP_NAME);
/* display form */
OUT("<p>Please enter your name:</p>");
OUT("<form action=\"welcome\"><input name=\"name\" autofocus> <input type=\"submit\" value=\"Run\"></form>");
/* try to get the query string value */
QSVAL qs_name; // query string value
if ( QS("name", qs_name) ) // if present, bid welcome
OUT("<p>Welcome %s, my dear friend!</p>", qs_name);
OUT("<p><a href=\"/\">Back to landing page</a></p>");
OUT_HTML_FOOTER;
}
else // page not found
{
RES_STATUS(404);
}
}
Complete 4-page application example is included in the package (see npp_app.cpp).
More examples are available here: Node++ examples.
Configuration file (bin/npp.conf) contains a handful of settings, starting with logLevel, httpPort, httpsPort, SSL certificate paths, database credentials and so on.
You can also add your own and read them in npp_app_init()
with npp_read_param_str() or npp_read_param_int().
Although not necessary, it’s good to have $NPP_DIR set in the environment, pointing to the project directory. Node++ engine always first looks in $NPP_DIR/<dir>
for the particular file, with <dir>
being one of the below:
src
(Required only for development)
npp_app.h
and npp_app.cpp
with npp_app_main()
inside.m
lib
(Required only for development)
users.sql
bin
nppmake
npp_app
, npp_svc
, npp_watcher
, npp_update
nppstart
, nppstop
npp.conf
strings.LL-CC
blacklist.txt
whitelist.txt
passwords.txt
res
Static resources. The whole tree under res
is publicly available. All the files are read on startup and served straight from the memory. File list is updated once a minute.
resmin
Static resources to be minified. The whole tree under resmin
is publicly available. All the files are read on startup, minified and served straight from the memory. File list is updated once a minute.
snippets
Static parts of rendered content, i.e. HTML or markdown snippets.
logs