BCHS Logo

BCHS

JSON

BSD, C, httpd, SQLite

BCHS works especially well for JSON web applications, which is the de jure method for building dynamic web sites. These applications have a well-defined split between back-end (BCHS), transport protocol (JSON), and front-end (JavaScript, CSS, and HTML5). And there are plenty of tools available to build, document, and deploy your work. Why is this an improvement over simply emitting HTML?

Most (all?) complaints of JSON web applications fall to poor front-end decisions: using enormous frameworks, CSP violations, and really just plain shitty code. In this short document, I'll sketch out how to set up your BCHS environment for JSON applications. For a full working system using this method, see dblg.

Begin with the actual web application source. I use kcgi(3) and use pledge(2) (so it requires OpenBSD, of course) to safeguard our operating system. In this example, I just emit a simple greeting in a JSON container.

    1 #include <err.h>
    2 #include <stdarg.h>
    3 #include <stdint.h>
    4 #include <stdlib.h>
    5 #include <unistd.h>
    6 
    7 #include <kcgi.h>
    8 #include <kcgijson.h>
    9 
   10 int
   11 main(void)
   12 {
   13   struct kreq r;
   14   struct kjsonreq req;
   15   const char *page = "index";
   16 
   17   if (KCGI_OK != khttp_parse(&r, NULL, 0, &page, 1, 0))
   18     return(EXIT_FAILURE);
   19 
   20   if (-1 == pledge("stdio", NULL)) 
   21     err(EXIT_FAILURE, "pledge");
   22 
   23   khttp_head(&r, kresps[KRESP_STATUS], 
   24     "%s", khttps[KHTTP_200]);
   25   khttp_head(&r, kresps[KRESP_CONTENT_TYPE], 
   26     "%s", kmimetypes[r.mime]);
   27   khttp_body(&r);
   28   kjson_open(&req, &r);
   29   kjson_obj_open(&req);
   30   kjson_putstringp(&req, "greeting", "hello, world");
   31   kjson_obj_close(&req);
   32   kjson_close(&req);
   33   khttp_free(&r);
   34   return(EXIT_SUCCESS);
   35 }

In most large systems, seperate people work the front-end (HTML5, CSS, JS, etc.) and the back-end (BCHS). We can document the interface between this by using Swagger, which hooks into JSON Schema to document the input and output of each resource.

    1 {
    2  "swagger": "2.0",
    3  "info": {
    4   "title": "test",
    5   "description": "this is sample documentation",
    6   "contact": {
    7    "name": "Kristaps Dzonsons",
    8    "email": "kristaps@bsd.lv"
    9   },
   10   "version": "0.0.1"
   11  },
   12  "paths": {
   13   "/index.json" : {
   14    "get": {
   15     "description": "nice greeting",
   16     "produces": [ "application/json" ],
   17     "responses": {
   18      "200": {
   19        "description": "success",
   20        "schema": { 
   21         "type": "object",
   22         "properties": {
   23          "greeting": {
   24           "description": "a greeting",
   25           "type": "string"
   26          }
   27         },
   28         "required": [ "greeting" ]
   29        }
   30      }
   31     }
   32    }
   33   }
   34  }
   35 }

Front-end work! In this incredibly simple example, we use AJAX to asynchronously invoke our web application and put the result into an identified element. We use vanilla JS and pay deference to CSP by processing fully in the script. You'll obviously need to put your own application URL in the loader.

    1 <!DOCTYPE html>
    2 <html>
    3   <head>
    4     <meta charset="utf-8" /> 
    5     <title>sample</title>
    6     <script>
    7     function success(resp) {
    8       var res;
    9       try {
   10         res = JSON.parse(resp);
   11       } catch (error) {
   12         return;
   13       }
   14       document.getElementById('greeting').appendChild
   15         (document.createTextNode(res.greeting));
   16     }
   17     document.addEventListener('DOMContentLoaded', function() {
   18       var xmh = new XMLHttpRequest();
   19       xmh.onreadystatechange = function() {
   20         if (xmh.readyState === 4 && xmh.status === 200)
   21           success(xmh.responseText);
   22       };
   23       xmh.open('GET', '/cgi-bin/app/index.json', true);
   24       xmh.send(null);
   25     });
   26     </script>
   27   </head>
   28   <body>
   29     <span id="greeting"></span>
   30   </body>
   31 </html>