A lightweight RESTful API for managing todo items, built entirely in C. This project demonstrates how to build web services at a low level using standard C libraries.
┌────────────┐ ┌─────────────┐ ┌─────────────┐
│ │ │ │ │ │
│ Client │◄────► HTTP API │◄────► SQLite │
│ │ │ │ │ Database │
└────────────┘ └─────────────┘ └─────────────┘
│
│
┌────▼────┐
│ │
│ JSON │
│ │
└─────────┘
- Complete CRUD operations (Create, Read, Update, Delete)
- RESTful design following HTTP method conventions
- SQLite database for data persistence
- JSON request/response format
- Modular, maintainable C code structure
- Extensive testing capabilities
- Memory-safe implementations with proper cleanup
- Error handling with descriptive messages
REST (Representational State Transfer) is an architectural style for designing networked applications. Unlike SOAP or RPC which focus on actions, REST emphasizes resources and states.
Key principles of REST:
- Statelessness: Each request contains all information needed to process it
- Client-Server Architecture: Separation of concerns between UI/client and data storage
- Uniform Interface: Standard methods to interact with resources
- Resource-Based: Everything is a resource identified by a unique URI
- Representation: Resources can be represented in different formats (JSON, XML, etc.)
This API implements the standard HTTP methods for CRUD operations:
| HTTP Method | CRUD Operation | Description |
|---|---|---|
| GET | Read | Retrieve resource(s) |
| POST | Create | Create a new resource |
| PUT | Update | Update an existing resource |
| DELETE | Delete | Remove a resource |
- libmicrohttpd: Small C library that makes it easy to run an HTTP server
- libsqlite3: C library for SQLite, a self-contained, serverless database engine
- libjansson: C library for encoding, decoding, and manipulating JSON data
- libcurl: Client-side URL transfer library (used for testing)
- CMake: Cross-platform build system generator
For Debian/Ubuntu:
sudo apt-get update
sudo apt-get install build-essential cmake libcurl4-openssl-dev libsqlite3-dev libmicrohttpd-dev libjansson-devmkdir -p build
cd build
cmake ..
makeStart the server:
./build/src/todo_apiThe server will listen on port 8080 by default.
curl -X POST http://localhost:8080/todos -H "Content-Type: application/json" -d '{"title":"Buy groceries","description":"Get milk, bread, and eggs"}'curl http://localhost:8080/todoscurl http://localhost:8080/todos/1curl -X PUT http://localhost:8080/todos/1 -H "Content-Type: application/json" -d '{"title":"Buy groceries","description":"Get milk, bread, eggs, and cheese","completed":true}'curl -X DELETE http://localhost:8080/todos/1For easier development, use the management script:
./manage.sh build # Build the project
./manage.sh run # Run the server
./manage.sh test # Run unit tests
./manage.sh api-test # Test API endpointsrest-api/
├── CMakeLists.txt # Main CMake configuration
├── manage.sh # Management script
├── src/ # Source code
│ ├── CMakeLists.txt # Source CMake configuration
│ ├── main.c # Entry point
│ ├── core/ # Core functionality
│ │ ├── todo.h # Todo structure definition
│ │ └── todo.c # Todo operations
│ ├── db/ # Database operations
│ │ ├── database.h # Database interface
│ │ └── database.c # SQLite implementation
│ └── http/ # HTTP handling
│ ├── server.h # Server interface
│ ├── server.c # Server implementation
│ ├── handlers.h # Request handlers interface
│ └── handlers.c # Request handlers implementation
├── tests/ # Unit tests
│ ├── CMakeLists.txt # Test CMake configuration
│ └── test_todo.c # Todo unit tests
└── scripts/ # Helper scripts
└── test_api.sh # API test script
The central data model representing a task with:
- Unique identifier
- Title and description
- Completion status
- Timestamps for creation and updates
Operations include creating, retrieving, updating, and deleting todos.
Manages all interactions with SQLite:
- Initializes the database and creates tables
- Executes SQL statements for CRUD operations
- Provides a callback mechanism for processing query results
SQLite was chosen for its simplicity, zero-configuration, and self-contained nature.
Built with libmicrohttpd to:
- Start and stop the HTTP server
- Route requests to appropriate handlers
- Parse request URLs, methods, and bodies
- Send formatted responses with correct status codes
Implements the business logic for each API endpoint:
- Parsing JSON requests using jansson
- Performing operations on the todo structure
- Generating JSON responses
- Error handling with appropriate HTTP status codes
The API takes care to properly manage memory:
- Dynamic allocations are tracked and freed
- String buffers are properly sized and null-terminated
- JSON objects are reference-counted and properly released
Comprehensive error handling includes:
- Database errors with detailed messages
- JSON parsing errors
- HTTP request validation
- Resource not found errors
- Server initialization failures
libmicrohttpd handles concurrency with a thread-per-connection model, allowing the API to serve multiple clients simultaneously. The SQLite database is configured for thread-safety.
The project implements multiple testing layers:
- Unit Tests: Test individual functions in isolation
- Integration Tests: Test the interaction between components
- API Tests: Test HTTP endpoints end-to-end
- Connection Pooling: The server uses connection pooling to reduce overhead
- Prepared Statements: SQL statements are prepared to improve database performance
- Minimal Copying: Data is processed with minimal copying between memory regions
- Efficient JSON Parsing: Uses jansson's stream parsing for large payloads
- Input Validation: All client inputs are validated before processing
- SQL Injection Prevention: Uses prepared statements to prevent SQL injection
- Memory Safety: Careful buffer management to prevent overflows
- Error Information: Limited error details exposed to clients
Contributions are welcome! Feel free to open issues or submit pull requests.
When contributing, please:
- Follow the existing code style
- Add tests for new functionality
- Ensure all tests pass
- Update documentation as needed
If you find this project helpful, consider buying me a coffee:
This project is licensed under the MIT License - see the LICENSE file for details.
