A command-line HTTP client written in C++ that talks to a remote REST API simulating an online movie library. No HTTP libraries — sockets only. JSON parsing is handled by nlohmann/json, which is bundled in the repo.
The server lives at 63.32.125.183:8081. Two classes of users exist: admin accounts (manage normal users) and normal user accounts (manage movies and collections).
makeProduces a client binary. Clean with make clean.
./clientType commands one per line. The client opens a fresh TCP connection for each command, sends the request, reads the response, and closes the socket. The only exception is add_collection, which needs one connection to create the collection and then one connection per movie added to it (the server only accepts one movie per request).
| Command | What it does |
|---|---|
login_admin |
Prompts username and password, logs in as admin. Sets a session cookie. |
add_user |
Creates a normal user under the logged-in admin. Prompts username and password. |
get_users |
Lists all normal users belonging to the admin. |
delete_user |
Deletes a normal user by username. |
logout_admin |
Logs out the admin session, clears cookies and JWT. |
| Command | What it does |
|---|---|
login |
Prompts admin_username, username, password. Sets session cookie. |
get_access |
Requests a JWT token granting library access. |
get_movies |
Lists all movies (requires JWT). |
get_movie |
Shows full details of a movie by id (requires JWT). |
add_movie |
Adds a movie. Prompts title, year, description, rating (requires JWT). |
update_movie |
Updates a movie by id with the same fields (requires JWT). |
delete_movie |
Deletes a movie by id (requires JWT). |
get_collections |
Lists all collections (requires JWT). |
get_collection |
Shows a collection's movies by id (requires JWT). |
add_collection |
Creates a collection and bulk-adds movies. Prompts title, num_movies, then movie_id[i] per movie. |
delete_collection |
Deletes a collection by id. Must be the owner. |
add_movie_to_collection |
Adds one movie to an existing collection. Prompts collection_id and movie_id. |
delete_movie_from_collection |
Removes a movie from a collection. Prompts both IDs. |
logout |
Logs out the normal user session. |
| Command | What it does |
|---|---|
exit |
Quits the program. |
Each iteration of the main loop in client.cpp:
- Opens a TCP socket and connects to the server.
- Reads a command from
stdin. - Builds the HTTP request string in memory.
- Sends it and reads the full response (re-
reallocs the buffer if the response is larger thanBUFSIZ). - Parses and prints the result, then closes the socket.
The connection is closed after every request (Connection: close). This matches what the server side expects.
Two pieces of state are kept across commands:
- cookies — an
unordered_map<string, string>populated fromSet-Cookieheaders. Sent back on every request in aCookie:header. - jwt — a raw
char *extracted from the{"token":"..."}field whenget_accesssucceeds. Sent asAuthorization: Bearer <token>on any library request.
On logout or logout_admin, both are cleared.
Four builders exist: compute_get_request, compute_post_request, compute_put_request, and compute_delete_request. They write directly into a heap-allocated char buffer using sprintf and strcat, appending headers line by line with \r\n after each. The cookie map is serialised into a single Cookie: header (key=value pairs joined by ; ).
POST and PUT requests also write Content-Type and Content-Length headers, then append the body after the blank line.
recv_resp reads from the socket in BUFSIZ chunks until recv returns 0, growing the buffer with realloc as needed.
read_resp then:
- Checks for a
{"message":...}or{"error":...}JSON field and prints it directly. - For commands that return structured data (
get_users,get_movies,get_movie, etc.), it seeks past the\r\n\r\nheader terminator and feeds the body intonlohmann::json::parse.
HTTP status codes between 200–299 are treated as success; everything else as an error. interpret_code prints either SUCCESS or ERROR with the numeric code and reason phrase.
This command cannot follow the single-connection pattern because the server requires the collection to exist before movies can be added to it, and each movie addition is a separate POST on a different path. The function handle_add_collection in client_lib.cpp:
- Sends
POST /api/v1/tema/library/collectionsand reads the new collection ID from the response body. - Opens a new socket for each movie and sends
POST /api/v1/tema/library/collections/:id/movies.
If any individual movie add fails, the loop stops early. The collection itself still exists on the server at that point.
nlohmann/json.hpp is a single-header library included directly in the repo. It is used only for serialising request bodies (json::dump()) and deserialising response bodies (json::parse()). The choice over parson was made because nlohmann integrates cleanly with C++ std::string and operator overloading makes the code shorter.
client.cpp — main loop: socket lifecycle, command dispatch
client_lib.hpp — constants, path macros, command IDs, function declarations
client_lib.cpp — command handlers, request builders, response parser
requests.cpp — low-level HTTP message assembly (GET/POST/PUT/DELETE)
helpers.cpp — socket helpers (send_to_server, compute_message, etc.)
buffer.cpp/.hpp — dynamic byte buffer used by receive_from_server
util.h — DIE macro
nlohmann/ — bundled JSON library
Makefile