C based API
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -61,3 +61,7 @@ target/
|
|||||||
# meteor
|
# meteor
|
||||||
app.tar.gz
|
app.tar.gz
|
||||||
.idea/
|
.idea/
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.out
|
||||||
|
|
||||||
|
|||||||
19
apiv2/Makefile
Normal file
19
apiv2/Makefile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
CC = gcc
|
||||||
|
CFLAGS = -I. -I./include -I/opt/homebrew/include -std=c99 -Wall $(shell pkg-config --cflags jansson)
|
||||||
|
SOURCES = src/main.c src/database.c mongoose.c sqlite3.c
|
||||||
|
OBJECTS = $(SOURCES:.c=.o)
|
||||||
|
TARGET = api_server
|
||||||
|
LIBS = -lpthread -ldl $(shell pkg-config --libs jansson)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) $(OBJECTS) -o $@ $(LIBS)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJECTS) $(TARGET)
|
||||||
BIN
apiv2/api_server
Executable file
BIN
apiv2/api_server
Executable file
Binary file not shown.
BIN
apiv2/database.db
Normal file
BIN
apiv2/database.db
Normal file
Binary file not shown.
9
apiv2/include/database.h
Normal file
9
apiv2/include/database.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef DATABASE_H
|
||||||
|
#define DATABASE_H
|
||||||
|
|
||||||
|
int db_init();
|
||||||
|
char* db_query(const char *query);
|
||||||
|
int db_insert(const char *value);
|
||||||
|
void db_close();
|
||||||
|
|
||||||
|
#endif
|
||||||
19019
apiv2/mongoose.c
Normal file
19019
apiv2/mongoose.c
Normal file
File diff suppressed because it is too large
Load Diff
3166
apiv2/mongoose.h
Normal file
3166
apiv2/mongoose.h
Normal file
File diff suppressed because it is too large
Load Diff
257679
apiv2/sqlite3.c
Normal file
257679
apiv2/sqlite3.c
Normal file
File diff suppressed because it is too large
Load Diff
13425
apiv2/sqlite3.h
Normal file
13425
apiv2/sqlite3.h
Normal file
File diff suppressed because it is too large
Load Diff
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