From 36175c3ce4104e06f69a13398a89261d68e380fe Mon Sep 17 00:00:00 2001 From: pedrofnseca Date: Sat, 28 Sep 2024 17:21:55 -0300 Subject: [PATCH] refactor: implement headers file --- src/handler.c | 65 ++++++++++++++++++++ src/headers/handler.h | 64 +++---------------- src/headers/pg.h | 77 ++--------------------- src/headers/response_builder.h | 19 ++---- src/headers/user_handler.h | 109 +++------------------------------ src/headers/utils.h | 38 +++--------- src/pg.c | 75 +++++++++++++++++++++++ src/response_builder.c | 16 +++++ src/user_handler.c | 108 ++++++++++++++++++++++++++++++++ src/utils.c | 40 ++++++++++++ 10 files changed, 342 insertions(+), 269 deletions(-) create mode 100644 src/handler.c create mode 100644 src/pg.c create mode 100644 src/response_builder.c create mode 100644 src/user_handler.c create mode 100644 src/utils.c diff --git a/src/handler.c b/src/handler.c new file mode 100644 index 0000000..f4e18d2 --- /dev/null +++ b/src/handler.c @@ -0,0 +1,65 @@ +#include "headers/response_builder.h" +#include "headers/user_handler.h" +#include +#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; +} \ No newline at end of file diff --git a/src/headers/handler.h b/src/headers/handler.h index 6333d80..ca71502 100644 --- a/src/headers/handler.h +++ b/src/headers/handler.h @@ -1,62 +1,18 @@ -#include "headers/response_builder.h" -#include "headers/user_handler.h" +#ifndef HANDLER_H +#define HANDLER_H + #include -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; -} \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/headers/pg.h b/src/headers/pg.h index 9370893..ccc94c9 100644 --- a/src/headers/pg.h +++ b/src/headers/pg.h @@ -1,6 +1,6 @@ -#include -#include -#include +#ifndef PG_H +#define PG_H + #include #define database "*****" @@ -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 \ No newline at end of file diff --git a/src/headers/response_builder.h b/src/headers/response_builder.h index dfafc5b..934aa2b 100644 --- a/src/headers/response_builder.h +++ b/src/headers/response_builder.h @@ -1,16 +1,9 @@ -#include -#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 +#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 diff --git a/src/headers/user_handler.h b/src/headers/user_handler.h index da02428..19bb3c4 100644 --- a/src/headers/user_handler.h +++ b/src/headers/user_handler.h @@ -1,107 +1,18 @@ -#include "headers/pg.h" -#include -#include +#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 - }; -} \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/headers/utils.h b/src/headers/utils.h index 245bc05..76e67c3 100644 --- a/src/headers/utils.h +++ b/src/headers/utils.h @@ -1,3 +1,6 @@ +#ifndef UTILS_H +#define UTILS_H + #include #include #include @@ -22,37 +25,12 @@ typedef struct { char *email; } USER; -char *simple_message(const char *message_str) { - char *formatted_message = NULL; - - size_t formatted_message_size = strlen(message_str) + 20; - formatted_message = (char *)malloc(formatted_message_size); - - if (formatted_message) { - snprintf(formatted_message, formatted_message_size, "{\"message\": \"%s\"}", message_str); - } - - return formatted_message; -} +char *simple_message(const char *message_str); -bool validate_route(const char *url, char *route) { - return strstr(url, route) != NULL; -} +HTTP_response validate_result(char *result); -bool validate_method(const char *method, char *valid_method) { - return strcmp(method, valid_method) == 0; -} +bool validate_method(const char *method, char *valid_method); -HTTP_response validate_result(char *result) { - if (result == NULL) { - return (HTTP_response){ - .body = simple_message("Internal server error"), - .status = INTERNAL_SERVER_ERROR - }; - } +bool validate_route(const char *url, char *route); - return (HTTP_response){ - .body = result, - .status = OK - }; -} \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/pg.c b/src/pg.c new file mode 100644 index 0000000..5f2d1c3 --- /dev/null +++ b/src/pg.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include "headers/pg.h" + +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; +} diff --git a/src/response_builder.c b/src/response_builder.c new file mode 100644 index 0000000..b23d358 --- /dev/null +++ b/src/response_builder.c @@ -0,0 +1,16 @@ +#include +#include "headers/utils.h" + +struct MHD_Response *HTTP_build_response_JSON(const char *message) { + struct MHD_Response *response; + + response = MHD_create_response_from_buffer(strlen(message), (void *)message, MHD_RESPMEM_PERSISTENT); + + if (!response) + return NULL; + + MHD_add_response_header(response, "Content-Type", "application/json"); + MHD_add_response_header(response, "Access-Control-Allow-Origin", "*"); + + return response; +} \ No newline at end of file diff --git a/src/user_handler.c b/src/user_handler.c new file mode 100644 index 0000000..fd2c4df --- /dev/null +++ b/src/user_handler.c @@ -0,0 +1,108 @@ +#include +#include +#include "headers/user_handler.h" +#include "headers/pg.h" + +HTTP_response get_all(const char *url) { + const char *query = "SELECT * FROM users"; + + char *result = executeQueryToJson(query); + + return validate_result(result); +} + +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 + }; + } + + char query[64]; + snprintf(query, sizeof(query), "SELECT * FROM users WHERE id = %s", user_id); + + char *result = executeQueryToJson(query); + + return validate_result(result); +} + +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 + }; +} \ No newline at end of file diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..3057243 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include "headers/utils.h" + +char *simple_message(const char *message_str) { + char *formatted_message = NULL; + + size_t formatted_message_size = strlen(message_str) + 20; + formatted_message = (char *)malloc(formatted_message_size); + + if (formatted_message) { + snprintf(formatted_message, formatted_message_size, "{\"message\": \"%s\"}", message_str); + } + + return formatted_message; +} + +bool validate_route(const char *url, char *route) { + return strstr(url, route) != NULL; +} + +bool validate_method(const char *method, char *valid_method) { + return strcmp(method, valid_method) == 0; +} + +HTTP_response validate_result(char *result) { + if (result == NULL) { + return (HTTP_response){ + .body = simple_message("Internal server error"), + .status = INTERNAL_SERVER_ERROR + }; + } + + return (HTTP_response){ + .body = result, + .status = OK + }; +} \ No newline at end of file