C based API
This commit is contained in:
88
apiv2/src/database.c
Normal file
88
apiv2/src/database.c
Normal file
@@ -0,0 +1,88 @@
|
||||
#include "database.h"
|
||||
#include <sqlite3.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <jansson.h>
|
||||
|
||||
static sqlite3 *db;
|
||||
|
||||
int db_init() {
|
||||
int rc = sqlite3_open("database.db", &db);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Initialize tables if necessary
|
||||
const char *sql = "CREATE TABLE IF NOT EXISTS data (id INTEGER PRIMARY KEY, value TEXT);";
|
||||
char *errmsg = 0;
|
||||
rc = sqlite3_exec(db, sql, 0, 0, &errmsg);
|
||||
if (rc != SQLITE_OK) {
|
||||
sqlite3_free(errmsg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
char* db_query(const char *query) {
|
||||
// Prepare SQL statement
|
||||
const char *sql = "SELECT * FROM data WHERE value LIKE ?;";
|
||||
sqlite3_stmt *stmt;
|
||||
char *response = NULL;
|
||||
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return strdup("{\"error\": \"Failed to prepare statement\"}");
|
||||
}
|
||||
|
||||
// Bind the query parameter
|
||||
sqlite3_bind_text(stmt, 1, query, -1, SQLITE_TRANSIENT);
|
||||
|
||||
// Build JSON response
|
||||
json_t *json_arr = json_array();
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
json_t *json_obj = json_object();
|
||||
int id = sqlite3_column_int(stmt, 0);
|
||||
const unsigned char *value = sqlite3_column_text(stmt, 1);
|
||||
|
||||
json_object_set_new(json_obj, "id", json_integer(id));
|
||||
json_object_set_new(json_obj, "value", json_string((const char *)value));
|
||||
|
||||
json_array_append_new(json_arr, json_obj);
|
||||
}
|
||||
|
||||
char *json_str = json_dumps(json_arr, JSON_INDENT(2));
|
||||
response = strdup(json_str);
|
||||
|
||||
// Cleanup
|
||||
free(json_str);
|
||||
json_decref(json_arr);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
int db_insert(const char *value) {
|
||||
const char *sql = "INSERT INTO data (value) VALUES (?);";
|
||||
sqlite3_stmt *stmt;
|
||||
int rc;
|
||||
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Bind the value parameter
|
||||
sqlite3_bind_text(stmt, 1, value, -1, SQLITE_TRANSIENT);
|
||||
|
||||
// Execute the statement
|
||||
rc = sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if (rc != SQLITE_DONE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void db_close() {
|
||||
sqlite3_close(db);
|
||||
}
|
||||
113
apiv2/src/main.c
Normal file
113
apiv2/src/main.c
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "mongoose.h"
|
||||
#include "database.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <jansson.h>
|
||||
|
||||
static const char *s_http_port = "8001";
|
||||
static const char *s_root_dir = "."; // Serve current directory
|
||||
|
||||
static void handle_get(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
char query[256] = {0};
|
||||
char *response;
|
||||
|
||||
// Parse query parameter 'q'
|
||||
mg_http_get_var(&hm->query, "q", query, sizeof(query));
|
||||
|
||||
response = db_query(query);
|
||||
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", response);
|
||||
|
||||
free(response);
|
||||
}
|
||||
|
||||
static void handle_post(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
char *response;
|
||||
int result;
|
||||
|
||||
// Get the JSON data from the body
|
||||
char *body = malloc(hm->body.len + 1);
|
||||
memcpy(body, hm->body.buf, hm->body.len);
|
||||
body[hm->body.len] = '\0';
|
||||
|
||||
// Parse JSON data
|
||||
json_error_t error;
|
||||
json_t *root = json_loads(body, 0, &error);
|
||||
free(body);
|
||||
|
||||
if (!root) {
|
||||
mg_http_reply(c, 400, "Content-Type: text/plain\r\n", "Invalid JSON data: %s", error.text);
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract data from JSON
|
||||
const char *value = json_string_value(json_object_get(root, "value"));
|
||||
|
||||
if (!value) {
|
||||
mg_http_reply(c, 400, "Content-Type: text/plain\r\n", "Missing 'value' in JSON data");
|
||||
json_decref(root);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store data in the database
|
||||
result = db_insert(value);
|
||||
|
||||
if (result == 0) {
|
||||
mg_http_reply(c, 200, "Content-Type: text/plain\r\n", "Data stored successfully");
|
||||
} else {
|
||||
mg_http_reply(c, 500, "Content-Type: text/plain\r\n", "Failed to store data");
|
||||
}
|
||||
|
||||
json_decref(root);
|
||||
}
|
||||
|
||||
static void handle_api_call(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
if (mg_casecmp(&hm->method, "GET") == 0) {
|
||||
handle_get(c, hm);
|
||||
} else if (mg_casecmp(&hm->method, "POST") == 0) {
|
||||
handle_post(c, hm);
|
||||
} else {
|
||||
mg_http_reply(c, 405, "Content-Type: text/plain\r\n", "Method Not Allowed");
|
||||
}
|
||||
}
|
||||
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
|
||||
if (mg_match(hm->uri, mg_str("/api"), NULL)) {
|
||||
handle_api_call(c, hm);
|
||||
} else {
|
||||
struct mg_http_serve_opts opts = {.root_dir = s_root_dir};
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
|
||||
mg_mgr_init(&mgr);
|
||||
|
||||
// Initialize the database
|
||||
if (db_init() != 0) {
|
||||
printf("Failed to initialize database\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Starting RESTful API on port %s\n", s_http_port);
|
||||
|
||||
// Start listening for connections
|
||||
if (mg_http_listen(&mgr, s_http_port, fn, NULL) == NULL) {
|
||||
printf("Failed to create listener\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
mg_mgr_poll(&mgr, 1000);
|
||||
}
|
||||
|
||||
mg_mgr_free(&mgr);
|
||||
db_close();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user