JSON-RPC

Mongoose includes a set of functions to ease server-side processing by means of RPC methods.

struct mg_rpc

The RPC method handler structure. Each method has an entry in a linked list, each entry points to a string describing the pattern that will invoke it and the function that will be called to satisfy the method invocation, with a proper function argument.

struct mg_rpc {
  struct mg_rpc *next;              // Next in list
  struct mg_str method;             // Method pattern
  void (*fn)(struct mg_rpc_req *);  // Handler function
  void *fn_data;                    // Handler function argument
};

struct mg_rpc_req

The RPC request descriptor. An invoked method receives a descriptor containing the request, and a pointer to a function to be called to print the output response, with a proper function argument; e.g.: mg_pfn_realloc() or mg_pfn_iobuf()

struct mg_rpc_req {
  struct mg_rpc **head;  // RPC handlers list head
  struct mg_rpc *rpc;    // RPC handler being called
  mg_pfn_t pfn;          // Response printing function
  void *pfn_data;        // Response printing function data
  void *req_data;        // Arbitrary request data
  struct mg_str frame;   // Request, e.g. {"id":1,"method":"add","params":[1,2]}
};

mg_rpc_add()

void mg_rpc_add(struct mg_rpc **head, struct mg_str method_pattern,
                void (*handler)(struct mg_rpc_req *), void *handler_data);

Add the method method_pattern to the list head of RPC methods. Invoking this method will call handler and pass handler_data to it with the request (as r->fn_data in the usage example below).

Parameters:

  • head - the linked list pointer
  • method_pattern - the name of the method
  • handler - the RPC function performing the action for this method
  • handler_data - Arbitrary function data

NOTE: if method_pattern is an empty string, this handler will be called to process JSON-RPC responses. Handling responses might be necessary if the JSON requests are initiated by both sides.

Usage example:

struct mg_rpc *s_rpc_head = NULL;

static void rpc_sum(struct mg_rpc_req *r) {
  double a = 0.0, b = 0.0;
  mg_json_get_num(r->frame, "$.params[0]", &a);
  mg_json_get_num(r->frame, "$.params[1]", &b);
  mg_rpc_ok(r, "%g", a + b);
}

static void rpc_mul(struct mg_rpc_req *r) {//...}


  mg_rpc_add(&s_rpc_head, mg_str("sum"), rpc_sum, NULL);
  mg_rpc_add(&s_rpc_head, mg_str("mul"), rpc_mul, NULL);

mg_rpc_del()

void mg_rpc_del(struct mg_rpc **head, void (*handler)(struct mg_rpc_req *));

Remove the method with RPC function handler handler from the list head of RPC methods.

Parameters:

  • head - the linked list pointer
  • handler - the RPC function performing the action for this method, use NULL to deallocate all

Usage example:

struct mg_rpc *s_rpc_head = NULL;
// add methods
// ...

// Time to cleanup
mg_rpc_del(&s_rpc_head, rpc_mul);    // Deallocate specific handler
mg_rpc_del(&s_rpc_head, NULL);       // Deallocate all RPC handlers

mg_rpc_process()

void mg_rpc_process(struct mg_rpc_req *req);

Invoke the proper method for this request. If the requested method does not exist, mg_rpc_err() will be invoked and an error indication will be printed

Parameters:

  • req - a request

Usage example:

struct mg_rpc *s_rpcs = NULL;                               // Empty RPC list head
mg_rpc_add(&s_rpcs, mg_str("rpc.list"), mg_rpc_list, NULL); // Add rpc.list
// ... add more RPC methods

// On request, process the incoming frame
struct mg_str req = mg_str("{\"id\":1,\"method\":\"sum\",\"params\":[1,2]}");
struct mg_iobuf io = {0, 0, 0, 512};  // Empty IO buf, with 512 realloc granularity
struct mg_rpc_req r = {
  .head = &s_rpcs,        // RPC list head
  .rpc = NULL,            // This will be set by mg_rpc_process()
  .pfn = mg_pfn_iobuf,    // Printing function: print into the io buffer
  .pfn_data = &io,        // Pass our io buffer as a parameter
  .req_data = NULL,       // No specific request data
  .frame = req,           // Specify incoming frame
};

mg_rpc_process(&r);
if (io.buf != NULL) printf("Response: %s\n", (char *) io.buf);
mg_iobuf_free(&io);

mg_rpc_ok(), mg_rpc_vok()

void mg_rpc_ok(struct mg_rpc_req *, const char *fmt, ...);
void mg_rpc_vok(struct mg_rpc_req *, const char *fmt, va_list *ap);

Helper functions to print result frames

Parameters:

  • req - a request
  • fmt - format string in printf semantics. See mg_snprintf for the list of supported format specifiers

Usage example:

static void rpc_sum(struct mg_rpc_req *r) {
  double a = 0.0, b = 0.0;
  mg_json_get_num(r->frame, "$.params[0]", &a);
  mg_json_get_num(r->frame, "$.params[1]", &b);
  mg_rpc_ok(r, "%g", a + b);
}

mg_rpc_err(), mg_rpc_verr()

void mg_rpc_err(struct mg_rpc_req *, int code, const char *fmt, ...);
void mg_rpc_verr(struct mg_rpc_req *, int code, const char *fmt, va_list *);

Helper functions to print error frames

Parameters:

  • req - a request
  • fmt - format string in printf semantics. See mg_snprintf for the list of supported format specifiers

Usage example:

static void rpc_dosome(struct mg_rpc_req *r) {
  ...
  mg_rpc_err(r, -32109, "\"%.*s not found\"", len, &r->frame.buf[offset]);
}

mg_rpc_list()

void mg_rpc_list(struct mg_rpc_req *r);

Built-in RPC method to list all registered RPC methods. This function is not usually called directly, but registered as a method.

Parameters:

  • req - a request

Usage example:

mg_rpc_add(&s_rpc_head, mg_str("rpc.list"), mg_rpc_list, &s_rpc_head);

(see also mg_rpc_add())