Skip to content

Latest commit

ย 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ”— Mini HTTP REST API โ€” Java (No Frameworks)

A fully functional RESTful API built using pure Java with no external frameworks. This project demonstrates a deep understanding of how HTTP works under the hood by manually handling routing, request parsing, JSON serialization, and response formatting โ€” everything Spring Boot does automatically.


๐Ÿ“Œ Why This Project?

Most Java developers reach for Spring Boot without understanding what happens beneath it. This project was built to demonstrate:

  • How HTTP servers work at the socket level
  • Manual request routing and path variable extraction
  • Thread-safe data handling under concurrent requests
  • Clean layered architecture without framework scaffolding

๐Ÿ› ๏ธ Tech Stack

Tool Purpose
Java 11+ Core language
com.sun.net.httpserver Built-in JDK HTTP server
Gson JSON parsing and serialization
Maven Build management
JUnit 5 Unit testing

๐Ÿ“ Project Structure

mini-http-REST-api/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ main/java/
โ”‚   โ”‚   โ”œโ”€โ”€ Server.java               # Entry point โ€” starts the server
โ”‚   โ”‚   โ”œโ”€โ”€ handler/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ TaskHandler.java      # Routes requests, sends responses
โ”‚   โ”‚   โ”œโ”€โ”€ service/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ TaskService.java      # Business logic and validation
โ”‚   โ”‚   โ”œโ”€โ”€ repository/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ TaskRepository.java   # In-memory data storage
โ”‚   โ”‚   โ””โ”€โ”€ model/
โ”‚   โ”‚       โ””โ”€โ”€ Task.java             # Task model and Status enum
โ”‚   โ””โ”€โ”€ test/java/
โ”‚       โ””โ”€โ”€ TaskServiceTest.java      # Unit tests for service layer
โ”œโ”€โ”€ pom.xml
โ””โ”€โ”€ README.md

Layer Responsibilities

HTTP Request
     โ”‚
     โ–ผ
TaskHandler      โ†’ Parses request, routes to correct method, sends JSON response
     โ”‚
     โ–ผ
TaskService      โ†’ Validates input, applies business rules, throws errors
     โ”‚
     โ–ผ
TaskRepository   โ†’ Reads/writes to ConcurrentHashMap (in-memory store)
     โ”‚
     โ–ผ
Task             โ†’ Plain Java object (POJO) representing a task

๐Ÿš€ Getting Started

Prerequisites

  • Java 11 or higher
  • Maven 3.6+

Installation

# Clone the repository
git clone https://github.com/your-username/mini-http-api.git
cd mini-http-api

# Build the project
mvn clean install

# Run the server
mvn exec:java -Dexec.mainClass="Server"

The server will start on:

http://localhost:8080

๐Ÿ”Œ API Endpoints

Base URL: http://localhost:8080


โœ… Get All Tasks

GET /tasks

Response 200 OK:

[
  {
    "id": 1,
    "title": "Buy milk",
    "description": "From the supermarket",
    "status": "PENDING",
    "createdAt": "2024-01-15T10:30:00"
  }
]

โœ… Get a Single Task

GET /tasks/{id}

Response 200 OK:

{
  "id": 1,
  "title": "Buy milk",
  "description": "From the supermarket",
  "status": "PENDING",
  "createdAt": "2024-01-15T10:30:00"
}

Response 404 Not Found:

{
  "error": "Task with id 99 not found"
}

โœ… Create a Task

POST /tasks
Content-Type: application/json

Request Body:

{
  "title": "Buy milk",
  "description": "From the supermarket"
}

Response 201 Created:

{
  "id": 1,
  "title": "Buy milk",
  "description": "From the supermarket",
  "status": "PENDING",
  "createdAt": "2024-01-15T10:30:00"
}

Response 400 Bad Request (missing title):

{
  "error": "Title is required"
}

โœ… Update a Task

PUT /tasks/{id}
Content-Type: application/json

Request Body (all fields optional โ€” only send what you want to change):

{
  "title": "Buy oat milk",
  "status": "IN_PROGRESS"
}

Valid status values: PENDING, IN_PROGRESS, DONE

Response 200 OK:

{
  "id": 1,
  "title": "Buy oat milk",
  "description": "From the supermarket",
  "status": "IN_PROGRESS",
  "createdAt": "2024-01-15T10:30:00"
}

โœ… Delete a Task

DELETE /tasks/{id}

Response 204 No Content โ€” task deleted successfully

Response 404 Not Found:

{
  "error": "Task with id 1 not found"
}

๐Ÿ“Š HTTP Status Code Reference

Code Meaning When it's returned
200 OK Successful GET or PUT
201 Created Successful POST
204 No Content Successful DELETE
400 Bad Request Missing or invalid fields
404 Not Found Task ID does not exist
405 Method Not Allowed Unsupported HTTP method on a route
500 Internal Server Error Unexpected server-side error

โš™๏ธ How It Works Internally

Routing

There is no framework handling routing. TaskHandler.java manually matches the request path using string comparison and regex:

if (path.equals("/tasks")) { ... }
else if (path.matches("/tasks/\\d+")) { ... }

Thread Safety

The HttpServer processes requests on multiple threads simultaneously. To prevent race conditions:

  • ConcurrentHashMap is used instead of a regular HashMap for the data store
  • AtomicInteger is used for ID generation instead of a plain int counter

JSON Handling

Gson serializes Java objects to JSON responses and deserializes incoming request bodies โ€” the only external dependency in the project.


๐Ÿงช Running Tests

mvn test

Tests cover:

  • Creating a task successfully
  • Creating a task with a missing title โ†’ expects IllegalArgumentException
  • Getting a task that does not exist โ†’ expects IllegalArgumentException
  • Deleting a task that does not exist โ†’ expects IllegalArgumentException
  • Updating a task successfully

๐Ÿ’ก Key Design Decisions

Why no Spring Boot? Spring Boot is excellent for production, but it abstracts away HTTP fundamentals. This project was intentionally built without it to demonstrate understanding of what happens at the lower level.

Why in-memory storage? The focus of this project is the HTTP and architecture layer. A ConcurrentHashMap keeps the data layer simple so attention stays on routing, request handling, and thread safety. A database (PostgreSQL + JDBC) could be swapped in by only changing TaskRepository.java.

Why constructor injection? Each class receives its dependencies through the constructor rather than creating them internally. This makes unit testing straightforward โ€” you can pass a mock repository into TaskService without any framework.


๐Ÿ”ฎ Potential Extensions

  • Persist data to a PostgreSQL database via JDBC
  • Add query filtering: GET /tasks?status=PENDING
  • Add pagination: GET /tasks?page=1&size=5
  • Add request logging (method, path, response time)
  • Add API key authentication via request header

๐Ÿ‘ค Author

Kayongo Samuel Yongo GitHub โ€ข LinkedIn

About

My first Java project

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages