Skip to content

Commit

Permalink
refactor: implement headers file
Browse files Browse the repository at this point in the history
  • Loading branch information
PedroFnseca committed Sep 28, 2024
1 parent b5deb3f commit 36175c3
Show file tree
Hide file tree
Showing 10 changed files with 342 additions and 269 deletions.
65 changes: 65 additions & 0 deletions src/handler.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "headers/response_builder.h"
#include "headers/user_handler.h"
#include <setjmp.h>
#include "headers/handler.h"

jmp_buf exceptionBuffer;

#define TRY if (setjmp(exceptionBuffer) == 0)
#define CATCH else

void log_api(const char *url, const char *method) {
printf("[%s] %s\n", method, url);
}

enum MHD_Result default_handler(
void *cls, struct MHD_Connection *connection,
const char *url, const char *method, const char *version,
const char *upload_data, size_t *upload_data_size, void **con_cls) {

char *url_str = (char *)url;
char *method_str = (char *)method;
int ret;

struct MHD_Response *response;
HTTP_response response_api;

log_api(url_str, method_str);

TRY {
if (strcmp(url_str, "/") == 0) {
response_api = (HTTP_response){
.body = simple_message("Hello world!"),
.status = OK
};
}

else if (validate_route(url_str, "/users")) {
response_api = user_router(url_str, method_str, upload_data);
}

else {
response_api = (HTTP_response){
.body = simple_message("Not found"),
.status = NOT_FOUND
};
}
} CATCH {
response_api = (HTTP_response){
.body = simple_message("Internal server error"),
.status = INTERNAL_SERVER_ERROR
};

printf("Internal server error");
}

response = HTTP_build_response_JSON(response_api.body);

if (!response)
return MHD_NO;

ret = MHD_queue_response(connection, response_api.status, response);
MHD_destroy_response(response);

return ret;
}
64 changes: 10 additions & 54 deletions src/headers/handler.h
Original file line number Diff line number Diff line change
@@ -1,62 +1,18 @@
#include "headers/response_builder.h"
#include "headers/user_handler.h"
#ifndef HANDLER_H
#define HANDLER_H

#include <setjmp.h>

jmp_buf exceptionBuffer;
extern jmp_buf exceptionBuffer;

#define TRY if (setjmp(exceptionBuffer) == 0)
#define CATCH else

void log_api(const char *url, const char *method) {
printf("[%s] %s\n", method, url);
}

enum MHD_Result default_handler(void *cls, struct MHD_Connection *connection, const char *url,
const char *method, const char *version, const char *upload_data,
size_t *upload_data_size, void **con_cls) {
char *url_str = (char *)url;
char *method_str = (char *)method;
int ret;

struct MHD_Response *response;
HTTP_response response_api;

log_api(url_str, method_str);

TRY {
if (strcmp(url_str, "/") == 0) {
response_api = (HTTP_response){
.body = simple_message("Hello world!"),
.status = OK
};
}

else if (validate_route(url_str, "/users")) {
response_api = user_router(url_str, method_str, upload_data);
}

else {
response_api = (HTTP_response){
.body = simple_message("Not found"),
.status = NOT_FOUND
};
}
} CATCH {
response_api = (HTTP_response){
.body = simple_message("Internal server error"),
.status = INTERNAL_SERVER_ERROR
};

printf("Internal server error");
}

response = HTTP_build_response_JSON(response_api.body);

if (!response)
return MHD_NO;
void log_api(const char *url, const char *method);

ret = MHD_queue_response(connection, response_api.status, response);
MHD_destroy_response(response);
enum MHD_Result default_handler(
void *cls, struct MHD_Connection *connection,
const char *url, const char *method, const char *version,
const char *upload_data, size_t *upload_data_size, void **con_cls);

return ret;
}
#endif
77 changes: 4 additions & 73 deletions src/headers/pg.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef PG_H
#define PG_H

#include <libpq-fe.h>

#define database "*****"
Expand All @@ -13,73 +13,4 @@ char *executeQueryToJson(const char *query);

char *formatResultAsJson(PGresult *result);

char *executeQueryToJson(const char *query) {
PGconn *conn = PQconnectdb(
"user=" user
" password=" password
" dbname=" database
" host=" host
" port=" port
);

if (PQstatus(conn) != CONNECTION_OK) {
fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn));
PQfinish(conn);
return NULL;
}

PGresult *result = PQexec(conn, query);

if (PQresultStatus(result) != PGRES_TUPLES_OK) {
fprintf(stderr, "Query execution failed: %s", PQerrorMessage(conn));
PQclear(result);
PQfinish(conn);
return NULL;
}

char *jsonResult = formatResultAsJson(result);

PQclear(result);
PQfinish(conn);

return jsonResult;
}

char *formatResultAsJson(PGresult *result) {
int numFields = PQnfields(result);
int numRows = PQntuples(result);

// Calcula o tamanho total necessário para a string JSON -> para não estourar o buffer
int totalSize = numRows * (2 + numFields * 256) + numRows - 1 + 3;
// Cada campo contribui com pelo menos 256 caracteres, 2 para aspas e 1 para vírgula
// numRows - 1 é para as vírgulas entre objetos JSON
// 3 é para as chaves finais e terminador de string

char *json = (char *)malloc(totalSize);
json[0] = '\0';

if (numRows == 0) {
strcat(json, "[]");
return json;
}

for (int i = 0; i < numRows; ++i) {
strcat(json, "{");
for (int j = 0; j < numFields; ++j) {
if (j > 0) strcat(json, ",");
char *fieldName = PQfname(result, j);
char *fieldValue = PQgetvalue(result, i, j);

strcat(json, "\"");
strncat(json, fieldName, totalSize - strlen(json) - 5);
strcat(json, "\":\"");
strncat(json, fieldValue, totalSize - strlen(json) - 5);
strcat(json, "\"");
}
strcat(json, "}");
if (i < numRows - 1) strcat(json, ",");
}

return json;
}

#endif
19 changes: 6 additions & 13 deletions src/headers/response_builder.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
#include <microhttpd.h>
#include "headers/utils.h"

struct MHD_Response *HTTP_build_response_JSON(const char *message) {
struct MHD_Response *response;
#ifndef RESPONSE_BUILDER_H
#define RESPONSE_BUILDER_H

response = MHD_create_response_from_buffer(strlen(message), (void *)message, MHD_RESPMEM_PERSISTENT);

if (!response)
return NULL;
#include <microhttpd.h>
#include "utils.h"

MHD_add_response_header(response, "Content-Type", "application/json");
MHD_add_response_header(response, "Access-Control-Allow-Origin", "*");
struct MHD_Response *HTTP_build_response_JSON(const char *message);

return response;
}
#endif
109 changes: 10 additions & 99 deletions src/headers/user_handler.h
Original file line number Diff line number Diff line change
@@ -1,107 +1,18 @@
#include "headers/pg.h"
#include <string.h>
#include <stdio.h>
#ifndef USER_HANDLER_H
#define USER_HANDLER_H

HTTP_response get_all(const char *url) {
const char *query = "SELECT * FROM users";
#include "utils.h"

char *result = executeQueryToJson(query);
HTTP_response get_all(const char *url);

return validate_result(result);
}
HTTP_response get_one(const char *user_id);

HTTP_response get_one(const char *user_id) {
if (user_id == NULL) {
return (HTTP_response){
.body = simple_message("No user id provided"),
.status = BAD_REQUEST
};
}
HTTP_response create(const char *body);

char query[64];
snprintf(query, sizeof(query), "SELECT * FROM users WHERE id = %s", user_id);
HTTP_response update(const char *user_id, const char *body);

char *result = executeQueryToJson(query);
HTTP_response drop(const char *user_id);

return validate_result(result);
}
HTTP_response user_router(const char *url, const char *method, const char *body);

HTTP_response create(const char *body) {
if (body == NULL) {
return (HTTP_response){
.body = simple_message("No body provided"),
.status = BAD_REQUEST
};
}

char query[256];
snprintf(query, sizeof(query), "INSERT INTO users (name, email) VALUES ('%s', '%s')", "name", "email");

char *result = executeQueryToJson(query);

return validate_result(result);
}

HTTP_response update(const char *user_id, const char *body) {
if (user_id == NULL) {
return (HTTP_response){
.body = simple_message("No user id provided"),
.status = BAD_REQUEST
};
}

if (body == NULL) {
return (HTTP_response){
.body = simple_message("No body provided"),
.status = BAD_REQUEST
};
}

char query[256];
snprintf(query, sizeof(query), "UPDATE users SET name = '%s', email = '%s' WHERE id = %s", "name", "email", user_id);

char *result = executeQueryToJson(query);

return validate_result(result);
}

HTTP_response drop(const char *user_id) {
char query[64];
snprintf(query, sizeof(query), "DELETE FROM users WHERE id = %s", user_id);

char *result = executeQueryToJson(query);

return validate_result(result);
}

HTTP_response user_router(const char *url, const char *method, const char *body){
char *user_id = strstr(url, "/users/");
if (user_id != NULL) {
user_id += strlen("/users/");
}

if (validate_method(method, "GET")) {
if(user_id == NULL){
return get_all(url);
} else {
return get_one(user_id);
}
}

if (validate_method(method, "POST")) {
return create(body);
}

if (validate_method(method, "PUT")) {
return update(user_id, body);
}

if (validate_method(method, "DELETE")) {
return drop(user_id);
}

return (HTTP_response){
.body = simple_message("Not implemented"),
.status = NOT_IMPLEMENTED
};
}
#endif
Loading

0 comments on commit 36175c3

Please sign in to comment.