Skip to content

Commit 65f0002

Browse files
committed
Implement core book management features: REST API, validation, service layer, OpenAPI docs, and security configuration
1 parent 353d3bb commit 65f0002

File tree

17 files changed

+1000
-254
lines changed

17 files changed

+1000
-254
lines changed

README.md

Lines changed: 167 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,147 +2,233 @@
22

33
![Build](https://github.com/OKaluzny/spring-boot-rest-api-postgresql/actions/workflows/ci.yml/badge.svg)
44

5-
REST API CRUD application built with Spring Boot 4 and PostgreSQL.
5+
Educational project: REST API for managing books built with Spring Boot 4 and PostgreSQL.
66

7-
## Tech Stack
7+
## What You Will Learn
88

9-
- Java 17
10-
- Spring Boot 4.0.2
11-
- Spring Data JPA
12-
- Spring Security (Basic Auth)
13-
- PostgreSQL
14-
- Lombok
15-
- Docker
9+
- Building REST API with Spring Boot
10+
- Working with databases using Spring Data JPA
11+
- Data validation
12+
- Error handling (RFC 7807 Problem Details)
13+
- Basic Authentication
14+
- Swagger/OpenAPI documentation
15+
- Docker for database
16+
- Writing tests
1617

1718
## Requirements
1819

19-
- JDK 17+
20-
- Maven 3.8+
21-
- PostgreSQL 14+ (or Docker)
20+
Before starting, make sure you have installed:
2221

23-
## Quick Start
22+
- **Java 17+** — check: `java -version`
23+
- **Maven 3.8+** — check: `mvn -version`
24+
- **Docker** — check: `docker --version`
2425

25-
### 1. Start PostgreSQL
26+
## Quick Start (5 minutes)
27+
28+
### Step 1: Clone the repository
29+
30+
```bash
31+
git clone https://github.com/OKaluzny/spring-boot-rest-api-postgresql.git
32+
cd spring-boot-rest-api-postgresql
33+
```
34+
35+
### Step 2: Start PostgreSQL
2636

2737
```bash
2838
docker-compose up -d postgres
2939
```
3040

31-
### 2. Run Application
41+
Verify the container is running:
42+
```bash
43+
docker ps
44+
```
45+
You should see container `book-db` with status `Up`.
46+
47+
### Step 3: Run the application
3248

3349
```bash
3450
mvn spring-boot:run
3551
```
3652

37-
Application starts at `http://localhost:8080`
53+
Wait for the message:
54+
```
55+
Started Application in X seconds
56+
```
57+
58+
### Step 4: Open Swagger UI
3859

39-
### 3. Default Credentials
60+
Open in browser: **http://localhost:8080/swagger-ui.html**
4061

41-
- **API Auth:** `user:user`
42-
- **Database:** `postgres:postgres`
62+
Here you can interactively test the API.
4363

44-
## API Endpoints
64+
### Step 5: Authorization
65+
66+
API requires authentication:
67+
- **Username:** `user`
68+
- **Password:** `user`
4569

46-
| Method | Endpoint | Description |
47-
|--------|----------|-------------|
48-
| POST | `/api/books` | Create book |
49-
| GET | `/api/books` | Get all books |
50-
| GET | `/api/books/{id}` | Get book by ID |
51-
| GET | `/api/books?name={name}` | Search by name |
52-
| PUT | `/api/books/{id}` | Update book |
53-
| DELETE | `/api/books/{id}` | Delete book |
54-
| DELETE | `/api/books` | Delete all books |
70+
In Swagger UI click the **"Authorize"** button and enter these credentials.
5571

56-
### Example Request
72+
## Your First Request with curl
73+
74+
Create a book:
5775

5876
```bash
5977
curl -X POST http://localhost:8080/api/books \
6078
-H "Content-Type: application/json" \
61-
-H "Authorization: Basic dXNlcjp1c2Vy" \
62-
-d '{
63-
"name": "Java Programming",
64-
"description": "Learn Java",
65-
"tags": ["java", "programming"]
66-
}'
79+
-u user:user \
80+
-d '{"name": "Java Programming", "description": "Learn Java", "tags": ["java"]}'
6781
```
6882

69-
### Example Response
70-
83+
Response:
7184
```json
7285
{
7386
"id": 1,
7487
"name": "Java Programming",
7588
"description": "Learn Java",
76-
"tags": ["java", "programming"]
89+
"tags": ["java"]
7790
}
7891
```
7992

80-
## Configuration
93+
Get all books:
94+
```bash
95+
curl http://localhost:8080/api/books -u user:user
96+
```
97+
98+
## API Endpoints
99+
100+
| Method | URL | Description |
101+
|--------|-----|-------------|
102+
| `POST` | `/api/books` | Create a book |
103+
| `GET` | `/api/books` | Get all books (paginated) |
104+
| `GET` | `/api/books/{id}` | Get book by ID |
105+
| `GET` | `/api/books?name=Java` | Search by name |
106+
| `PUT` | `/api/books/{id}` | Update a book |
107+
| `DELETE` | `/api/books/{id}` | Delete a book |
81108

82-
Environment variables:
109+
### Pagination
83110

84-
| Variable | Default | Description |
85-
|----------|---------|-------------|
86-
| `DB_HOST` | localhost | Database host |
87-
| `DB_PORT` | 5432 | Database port |
88-
| `DB_NAME` | book_db | Database name |
89-
| `DB_USERNAME` | postgres | Database user |
90-
| `DB_PASSWORD` | postgres | Database password |
91-
| `SECURITY_USER` | user | API username |
92-
| `SECURITY_PASSWORD` | user | API password |
93-
| `SERVER_PORT` | 8080 | Application port |
111+
```
112+
GET /api/books?page=0&size=10&sort=name,asc
113+
```
94114

95-
## Docker
115+
- `page` — page number (starting from 0)
116+
- `size` — number of items per page
117+
- `sort` — sorting (field,direction)
96118

97-
### Run full stack
119+
## Project Structure
98120

99-
```bash
100-
docker-compose --profile full up -d
121+
```
122+
src/main/java/com/kaluzny/
123+
124+
├── Application.java # Entry point
125+
126+
├── config/ # Configuration
127+
│ ├── SecurityConfig.java # Security settings
128+
│ └── OpenApiConfig.java # Swagger settings
129+
130+
├── domain/ # Data layer
131+
│ ├── Book.java # JPA entity
132+
│ └── BookRepository.java # Repository
133+
134+
├── dto/ # Data Transfer Objects
135+
│ ├── BookCreateRequest.java
136+
│ ├── BookUpdateRequest.java
137+
│ ├── BookResponse.java
138+
│ └── BookMapper.java
139+
140+
├── service/ # Business logic
141+
│ └── BookService.java
142+
143+
├── exception/ # Error handling
144+
│ ├── BookNotFoundException.java
145+
│ └── GlobalExceptionHandler.java
146+
147+
└── web/ # REST controllers
148+
└── BookRestController.java
149+
```
150+
151+
## Architecture
152+
153+
```
154+
HTTP Request
155+
156+
┌─────────────────┐
157+
│ Controller │ ← Receives DTO, validation
158+
└────────┬────────┘
159+
160+
┌─────────────────┐
161+
│ Service │ ← Business logic
162+
└────────┬────────┘
163+
164+
┌─────────────────┐
165+
│ Repository │ ← Database operations
166+
└────────┬────────┘
167+
168+
┌─────────────────┐
169+
│ PostgreSQL │
170+
└─────────────────┘
101171
```
102172

103-
### Run only PostgreSQL
173+
## Stopping the Application
104174

175+
1. Stop Spring Boot: `Ctrl+C` in terminal
176+
2. Stop PostgreSQL:
105177
```bash
106-
docker-compose up -d postgres
178+
docker-compose down
107179
```
108180

109-
### Build image only
181+
## Running Tests
110182

111183
```bash
112-
docker build -t book-api .
184+
mvn test
113185
```
114186

115-
## Actuator Endpoints
187+
Tests use H2 in-memory database, PostgreSQL is not required.
116188

117-
- Health: `GET /actuator/health`
118-
- Info: `GET /actuator/info`
119-
- Metrics: `GET /actuator/metrics`
189+
## Useful Links
120190

121-
## Project Structure
191+
| URL | Description |
192+
|-----|-------------|
193+
| http://localhost:8080/swagger-ui.html | Swagger UI |
194+
| http://localhost:8080/v3/api-docs | OpenAPI JSON |
195+
| http://localhost:8080/actuator/health | Health check |
122196

123-
```
124-
src/main/java/com/kaluzny/
125-
├── Application.java # Entry point
126-
├── domain/
127-
│ ├── Book.java # JPA Entity
128-
│ └── BookRepository.java # Spring Data Repository
129-
├── exception/
130-
│ ├── BookNotFoundException.java
131-
│ └── GlobalExceptionHandler.java
132-
└── web/
133-
└── BookRestController.java # REST Controller
134-
```
197+
## Troubleshooting
135198

136-
## Testing
199+
### Error: "Port 8080 already in use"
137200

201+
Find and stop the process:
138202
```bash
139-
# Run tests (requires PostgreSQL)
140-
mvn test
203+
lsof -i :8080
204+
kill -9 <PID>
205+
```
206+
207+
### Error: "Connection refused" to PostgreSQL
141208

142-
# Skip tests
143-
mvn package -DskipTests
209+
Check that container is running:
210+
```bash
211+
docker ps
212+
docker-compose up -d postgres
144213
```
145214

215+
### Error: "docker: command not found"
216+
217+
Install Docker Desktop: https://www.docker.com/products/docker-desktop
218+
219+
## Technologies
220+
221+
| Technology | Version | Description |
222+
|------------|---------|-------------|
223+
| Java | 17 | Programming language |
224+
| Spring Boot | 4.0.2 | Framework |
225+
| Spring Data JPA | - | ORM for database |
226+
| Spring Security | - | Security |
227+
| PostgreSQL | 16 | Database |
228+
| Swagger/OpenAPI | 3.1 | API documentation |
229+
| Lombok | 1.18 | Reduce boilerplate |
230+
| JUnit 5 | - | Testing |
231+
146232
## License
147233

148234
MIT

pom.xml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@
3636
<groupId>org.springframework.boot</groupId>
3737
<artifactId>spring-boot-starter-data-jpa</artifactId>
3838
</dependency>
39-
<dependency>
40-
<groupId>org.springframework.boot</groupId>
41-
<artifactId>spring-boot-starter-data-rest</artifactId>
42-
</dependency>
4339
<dependency>
4440
<groupId>org.springframework.boot</groupId>
4541
<artifactId>spring-boot-starter-validation</artifactId>
@@ -60,6 +56,13 @@
6056
<scope>runtime</scope>
6157
</dependency>
6258

59+
<!-- OpenAPI / Swagger -->
60+
<dependency>
61+
<groupId>org.springdoc</groupId>
62+
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
63+
<version>2.8.4</version>
64+
</dependency>
65+
6366
<!-- Lombok -->
6467
<dependency>
6568
<groupId>org.projectlombok</groupId>
@@ -73,11 +76,21 @@
7376
<artifactId>spring-boot-starter-test</artifactId>
7477
<scope>test</scope>
7578
</dependency>
79+
<dependency>
80+
<groupId>org.springframework.boot</groupId>
81+
<artifactId>spring-boot-starter-webflux</artifactId>
82+
<scope>test</scope>
83+
</dependency>
7684
<dependency>
7785
<groupId>org.springframework.security</groupId>
7886
<artifactId>spring-security-test</artifactId>
7987
<scope>test</scope>
8088
</dependency>
89+
<dependency>
90+
<groupId>com.h2database</groupId>
91+
<artifactId>h2</artifactId>
92+
<scope>test</scope>
93+
</dependency>
8194
</dependencies>
8295

8396
<build>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.kaluzny.config;
2+
3+
import io.swagger.v3.oas.models.OpenAPI;
4+
import io.swagger.v3.oas.models.info.Contact;
5+
import io.swagger.v3.oas.models.info.Info;
6+
import io.swagger.v3.oas.models.info.License;
7+
import io.swagger.v3.oas.models.servers.Server;
8+
import org.springframework.context.annotation.Bean;
9+
import org.springframework.context.annotation.Configuration;
10+
11+
import java.util.List;
12+
13+
@Configuration
14+
public class OpenApiConfig {
15+
16+
@Bean
17+
public OpenAPI bookApiOpenAPI() {
18+
return new OpenAPI()
19+
.info(new Info()
20+
.title("Book API")
21+
.description("REST API for managing books - Educational Project")
22+
.version("1.0.0")
23+
.contact(new Contact()
24+
.name("Oleg Kaluzny")
25+
.url("https://github.com/OKaluzny"))
26+
.license(new License()
27+
.name("MIT License")
28+
.url("https://opensource.org/licenses/MIT")))
29+
.servers(List.of(
30+
new Server().url("http://localhost:8080").description("Local server")
31+
));
32+
}
33+
}

0 commit comments

Comments
 (0)