Automating my day job as a Landlord in ANSI C
An honest attempt at automating my life using the C programming language
I’m a landlord, and aside from collecting rent, I don’t have much to do. Honestly, among my few responsibilities, generating invoices is somewhat cumbersome—a consequence of my hesitance to purchase (and use) invoice generation software. I’d rather spend 10 hours automating my job than spend 10 minutes performing manual labor.
In this article, I relieve myself of the ‘tedious’ task of generating invoices for my tenants. We will create PDF invoices using an HTML and CSS frontend paired with a C backend.
Table of Contents
Sidenote to explain my programming language choice.
Compiling the Mongoose C library using GCC.
Building our API endpoints in pure C.
Serving JPEGS from a folder in pure C.
Storing tenant information in a C struct.
Sending JSON in a GET request C using the cJSON library.
Designing a receipt using HTML and CSS.
Connecting a HTMX frontend to our C backend.
Enabling CORS for the Mongoose C library. (CORS Missing Allow Header error)
Making POST Requests from HTMX to our Mongoose C backend.Making GET Requests from HTMX to our Mongoose C backend.Adding JavaScript to handle server responses better than HTMX.
Results
Sidenote : Explaining My Programming Language Choice
I hate Python. Python is a bad language for longevity. Python code I wrote 3 years ago often won’t run on my current setup.
JavaScript is just bad. JavaScript is the language of the coding proletariat.
TypeScript is unnecessarily complicated JavaScript. I know all you Microsoft simps use ‘any’ to declare your types. Foolish plebs all of you.
I wanted to learn HTMX. I believe React + 10 GB of node modules would be overkill for this project.
Step 1 : Compiling the Mongoose C Library using GCC
First, we create a file called Receipt.c
and set up a server using the Mongoose C library (not to be confused with the MongoDB client). We follow the Mongoose documentation and after compiling with GCC, we get a server running on port 8000.
Step 2 : Building Our API endpoints in pure C
a. Serving JPEGs from a Folder using Mongoose in Pure C
Next, we’ll build an API endpoint to serve static assets. I created a folder called Logo
to store my company’s logo. Then, we match the endpoint /api/logo, set our headers to image/jpeg
, and serve our JPEG file in response to a GET request..
If you’re coding along, you should see an image at http://localhost:8000/api/logo
b. Storing tenant information in a struct
Now we define a struct to hold our tenants’ information. We call this a Tenant
struct.
Then we initialize an array of Tenants as a global variable to use inside our ServerHandler function.
c. Serving information in a GET request
We need to create new GET requests for each piece of information we require. Using the Mongoose C library, this entails adding new endpoints to our ServerHandler
function. We hardcode the response and send it using the mg_printf
function.
If you’re coding along, then you should see a plain text response at http://localhost:8000/api/companyName
c. Sending JSON in C using the cJSON library.
Sending plain text is becoming cumbersome, so we'll use the cJSON library to send JSON objects using the Mongoose C library.
First, download the cJSON repository from GitHub and place cJSON.c
and cJSON.h
in our project folder. Your directory structure should resemble this:
Afterwards, we include the cJSON.h library at the top of Receipt.c and finally add cJSON.c to our GCC command.
Now, let's utilize cJSON. First, create a landlordDetailsJSON
object using the cJSON_CreateObject
function. Then, add strings to our landlordDetailsJSON
object using cJSON_AddStringToObject
. Next, convert our JSON into a string with cJSON_Print
. Finally, send the string from the endpoint api/getAllLandlordDetails
. Note that our content-type in mg_printf
should be application/json
.
If you’re coding along, then you’ll observe this response at the endpoint http://localhost:8000/api/getAllLandlordDetails
We repeat this for the tenant struct.
Step 4 : Designing a receipt using HTML and CSS
I designed a quick receipt template in Code Pen, here, using HTML and CSS. The design looks great in fullscreen mode on a PC).
Sidenote
Mongoose lacks hot-reloading (I could be wrong) so designing in Code Pen was much faster. Here’s the HTML+CSS receipt template I made. I use the Raleway font.
Step 5: Connecting a HTMX frontend to our C backend
I spent an hour trying to make a GET request with HTMX version 2. Whenever a request was made to localhost, an invalid path error occurred. Eventually, I gave up on learning HTMX version 2, only to discover that all the tutorials were using HTMX version 1.
Reader Requested update : The HTML frontend runs on port 3000 and the C backend on port 8000. Different servers lead to CORS issues.
We imported HTMX version 1.6 via CDN in our <head>
tag.
Impressive! This setup required no installation of 1 GB of node modules like React. Next, we need to set up CORS.
Part a : Enabling CORS for the Mongoose C library.
Using HTMX version 1, we encounter the error “CORS Missing Allow Header”.
Experience suggests handling this error on the server side. Therefore, we dug around in the Mongoose documentation and found how to enable CORS in Mongoose from a GitHub discussion. We need to set up a Preflight call before any requests are made inside our ServerHandler
function.
Part b : Making GET Requests from HTMX to our Mongoose C backend
Making GET requests in HTMX is straightforward. Inside an HTML element, such as a <div>
, you make a URL request using hx-get
. You generate an HTML change using hx-trigger
, specify the trigger location with hx-target
, and locate the change using hx-swap
. Here’s a sample GET request example:
Our trigger is set to "load". This means the HTTP request to Mongoose occurs immediately when our page loads. If your GET requests are working correctly, you should observe the following change.
Part b : Making GET Requests from HTMX to our Mongoose C backend
Update: I added about 20 GET requests to happen on page load, but some of them aren't functioning correctly. Additionally, I'm struggling with parsing JSON. I;ll probably replace HTMX with JavaScript.
Part c. Adding JavaScript and JSON
We replace most of our HTMX requests with two JavaScript GET requests.
The first request receives all the landlord details.
The second request receives all the tenant details.
We parse our responses into different HTML innerText nodes and we are done.
Results
We successfully paired a C backend with a JavaScript and HTMX frontend to generate invoices.
Here is a short video to showcasing our success. Here is the GitHub repo
.