In this day and age developing web services in C is a lost art. Here I will give details on how to start web development in C with FastCGI.
1. We will use Visual Studio Code for the development in order to use Makefile for building and running.
2. Install C/C++, C/C++ Extension Pack, C/C++ Themes, CMake Tools, Makefile Tools extensions for VS Code.
3. Create a folder src inside the root project directory with the file server.c with the following content.
#include "fcgi_stdio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* handle_request(const char *method, const char* uri) {
if (!method || !uri) {
return "Invalid request";
}
if (strcmp(method, "GET") == 0) { // GET request
if (strcmp(uri, "") == 0 || strcmp(uri, "/") == 0) {
return "42";
}
if (strcmp(uri, "/greet") == 0) {
return "Hello World";
}
if (strcmp(uri, "/health") == 0) {
return "ok";
}
return "Invalid GET endpoint";
}
return "Invalid request";
}
int main() {
while (FCGI_Accept() >= 0) {
const char *request_method = getenv("REQUEST_METHOD");
const char *request_uri = getenv("REQUEST_URI");
const char *response = handle_request(request_method, request_uri);
printf("Content-Type: text/plain\r\n"
"\r\n"
"%s\n", response);
}
return 0;
}
4. Create Makefile in the same src directory with the following content.
# Makefile for FastCGI server on macOS (Homebrew)
# Determine fcgi install path from Homebrew
BREW_PREFIX := $(shell brew --prefix fcgi)
# Compiler and flags
CC = gcc
CFLAGS = -Wall -O2 -I$(BREW_PREFIX)/include
LDFLAGS = -L$(BREW_PREFIX)/lib -lfcgi
# Directories
OUT_DIR = out
TARGET = $(OUT_DIR)/server
# Default target
all: $(TARGET)
# Build target
$(TARGET): server.c | $(OUT_DIR)
$(CC) $(CFLAGS) -o $(TARGET) server.c $(LDFLAGS)
# Ensure output folder exists
$(OUT_DIR):
mkdir -p $(OUT_DIR)
# Run FastCGI program (requires spawn-fcgi)
run: $(TARGET)
spawn-fcgi -a 127.0.0.1 -p 3000 -n ./$(TARGET)
# Clean build artifacts
clean:
rm -rf $(OUT_DIR)
The commands are as follows.
# Clean output
make clean
# Build
make
# Run
make run
5. Before this we need to have our dependencies installed which are fastcgi, spawn-cgi and nginx. spawn-cgi is required to run the fastcgi server in local for development. Nginx is fronting the FastCGI server to accept HTTP requests.
# Install FastCGI
brew install fcgi
# Check installed version
brew info fcgi
==> fcgi: stable 2.4.6 (bottled)
# Install spawn-cgi
brew install spawn-fcgi
# Install nginx
brew install nginx
6. Configure nginx which is a one time operation.
Update nginx.conf at /usr/local/etc/nginx/ with the below config.
http {
server {
listen 8080;
server_name localhost;
location / {
include fastcgi_params;
fastcgi_pass 127.0.0.1:3000;
}
}
}
We are starting the fastcgi server using make run and it runs on port 3000 as specified in the Makefile. Nginx runs on port 8080.
Test the config changes.
nginx -t
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Restart nginx.
brew services restart nginx
This should start the nginx server and make run should start the fastcgi server. We can check the endpoints using curl or programs.
curl http://127.0.0.1:8080
42
curl http://127.0.0.1:8080/greet
Hello World
curl http://127.0.0.1:8080/health
ok
This is a stepping stone for developing web application server with C and FastCGI. With C we need to write code to parse query params, get POST body all by ourself. This is some work. But that's one time setup. We are building our own web application server on top of FastCGI. We need to account for logging and other infrastructure code required for proper functioning of the web service.