In this blog post we will demonstrate how Mongoose can be used to implement a RESTful server. We’ll set up a key-value database server. This simple server can do three operations:

  • Get(key)
  • Set(key, value)
  • Delete(key)

This maps to the following RESTful API:

  • GET /key
  • PUT /key
  • DELETE /key

Let’s make it possible to plug different database implementations for this RESTful API. That means that we create internal DB interface which Mongoose code is going to use. So, db_plugin.h is going to look like this:

void *db_open(const char *db_path);
void db_close(void **db_handle);
enum { API_OP_GET, API_OP_SET, API_OP_DEL };
void db_op(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db, int op);

Now, let’s jump to Mongoose implementation. We initialise Mongoose, open database and create an event loop:

/* Open listening socket /
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = "web_root";
/
Open database /
if ((s_db_handle = db_open(s_db_path)) == NULL) {
fprintf(stderr, "Cannot open DB [%s]\n", s_db_path);
exit(EXIT_FAILURE);
}
/
Run event loop until signal is received */
printf("Starting RESTful server on port %s\n", s_http_port);
while (s_sig_num == 0) {
mg_mgr_poll(&mgr, 1000);
}

Here is the even handler function, which is going to catch RESTful requests and perform database action by calling db_op() database function.

static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
...
if (is_equal(&hm->method, &s_get_method)) {
db_op(nc, hm, &key, s_db_handle, API_OP_GET);
} else if (is_equal(&hm->method, &s_put_method)) {
db_op(nc, hm, &key, s_db_handle, API_OP_SET);
} else if (is_equal(&hm->method, &s_delele_method)) {
db_op(nc, hm, &key, s_db_handle, API_OP_DEL);
} else {
mg_printf(nc, "%s",
"HTTP/1.0 501 Not Implemented\r\n"
"Content-Length: 0\r\n\r\n");
}
...
}

The last step is to implement database interface, db_open(), db_close(), and db_op(), using one of the available database engines or implementing those “by hand”. For example, by using plain text files or any other method. We’re going to use a SQLite database engine, which does not require an external database process to be run. Instead, it executes DB operations in-process. In this way, it is very similar to Mongoose. In fact, Mongoose and SQLite have a lot in common, for example they both provide source code as an amalgamated, single C source file.

Here is the implementation of SQLite for database interface.

If you want to check out the full example again, check it out on GitHub.

Note that this RESTful server does not implement any authentication mechanism. Authentication examples will be covered in a future post.

To contact: send us a message or ask on the developer forum.