Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 192 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,193 @@
# API de estudiantes en Spring Boot
Api con dos endpoints REST: /api/health y /api/students tal como el proyecto PHP.
Ahora mismo tiene una base de datos InMemory para pruebas pero se configurara para usar una base de datos en MySQL. Con esta configuración cuando se reinicia el servidor los datos se pierden.
# Studentify - Student Management API

# Gradle
El proyecto usa Gradle como herramienta de compilación. El proyecto incluye gradlew y gradlew.bat para compilarlos en Linux y Windows respectivamente, sin la necesidad de instalar Gradle en el equipo.
A Spring Boot REST API for managing student records with health monitoring capabilities.

## Features

- **Student Management**: Create and retrieve student records
- **Health Monitoring**: API health check endpoint
- **Data Validation**: Comprehensive input validation with meaningful error messages
- **Database Integration**: JPA/Hibernate with MySQL support (H2 for testing)
- **Comprehensive Testing**: Unit tests, integration tests, and controller tests
- **Security**: Input validation and error handling

## API Endpoints

### Students

#### GET `/api/students`
Retrieves all students from the system.

**Response:**
```json
[
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com"
}
]
```

#### POST `/api/students`
Creates a new student.

**Request Body:**
```json
{
"name": "Jane Smith",
"email": "jane.smith@example.com"
}
```

**Response:** `201 Created`
```json
{
"id": 2,
"name": "Jane Smith",
"email": "jane.smith@example.com"
}
```

**Validation Rules:**
- `name`: Required, 2-100 characters
- `email`: Required, valid email format, unique, max 255 characters

### Health Check

#### GET `/api/health`
Returns API health status.

**Response:**
```json
{
"status": "success",
"message": "API is healthy",
"timestamp": "2025-01-31T10:30:45"
}
```

## Technology Stack

- **Java 21** - Programming language
- **Spring Boot 3.4.1** - Application framework
- **Spring Data JPA** - Data persistence
- **MySQL** - Production database
- **H2** - In-memory database for testing
- **JUnit 5** - Testing framework
- **Mockito** - Mocking framework
- **Gradle** - Build tool

## Getting Started

### Prerequisites

- Java 21 or higher
- MySQL database (for production)

### Building the Project

The project uses Gradle with wrapper scripts, so you don't need to install Gradle separately.

**Linux/macOS:**
```bash
./gradlew build
```

**Windows:**
```cmd
gradlew.bat build
```

### Running the Application

**Development (with H2 in-memory database):**
```bash
./gradlew bootRun
```

**Production (configure MySQL first):**
1. Update `application.properties` with your MySQL connection details
2. Run: `./gradlew bootRun --args='--spring.profiles.active=production'`

### Running Tests

**All tests:**
```bash
./gradlew test
```

**Integration tests only:**
```bash
./gradlew test --tests "*Integration*"
```

## Database Configuration

### Development (H2 - Default)
The application uses H2 in-memory database by default for development and testing.

### Production (MySQL)
Add these properties to `application.properties`:

```properties
spring.datasource.url=jdbc:mysql://localhost:3306/studentify
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
```

## Project Structure

```
src/
├── main/java/es/fpalanturing/studentify/
│ ├── controller/ # REST controllers
│ ├── model/ # Entity and DTO classes
│ ├── repository/ # Data access layer
│ └── service/ # Business logic layer
└── test/java/es/fpalanturing/studentify/
├── controller/ # Controller unit tests
├── service/ # Service unit tests
└── integration/ # Integration tests
```

## Error Handling

The API provides meaningful error responses:

- `400 Bad Request` - Invalid input data
- `500 Internal Server Error` - Server errors (duplicate email, database issues)

## Security Considerations

- Input validation on all endpoints
- Email uniqueness constraint
- Proper error handling without exposing sensitive information
- Data sanitization (trimming whitespace)

## Development

### Code Style
- Follow Java naming conventions
- Use Javadoc for public methods and classes
- Maintain comprehensive test coverage
- Handle exceptions appropriately

### Testing Strategy
- **Unit Tests**: Test individual components in isolation
- **Integration Tests**: Test complete request-response flow
- **Controller Tests**: Test REST endpoints with MockMvc

## Contributing

1. Fork the repository
2. Create a feature branch
3. Add tests for new functionality
4. Ensure all tests pass
5. Submit a pull request

## License

This project is developed for educational purposes.
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ repositories {

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-security'
runtimeOnly 'com.mysql:mysql-connector-j'
//runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package es.fpalanturing.studentify.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;

/**
* Security configuration for the Studentify application.
* Configures basic security headers and CORS settings.
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig {

/**
* Configures the security filter chain with basic security measures.
* @param http HttpSecurity configuration
* @return SecurityFilterChain with configured security settings
* @throws Exception if configuration fails
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// Disable CSRF for API endpoints (consider enabling for production with proper CSRF tokens)
.csrf(csrf -> csrf.disable())

// Configure authorization - all requests are permitted for this demo API
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/**").permitAll()
.requestMatchers("/h2-console/**").permitAll() // Allow H2 console access in development
.anyRequest().authenticated()
)

// Configure security headers
.headers(headers -> headers
.frameOptions().deny() // Prevent clickjacking
.contentTypeOptions().and() // Prevent MIME sniffing
.httpStrictTransportSecurity(hstsConfig -> hstsConfig
.maxAgeInSeconds(31536000) // 1 year
.includeSubdomains(true)
)
.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
);

// Special configuration for H2 console (development only)
http.headers().frameOptions().sameOrigin();

return http.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
package es.fpalanturing.studentify.controller;

import es.fpalanturing.studentify.model.Health;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


/**
* REST controller for health check operations.
* Provides endpoint to verify API health status.
*/
@RestController
@RequestMapping("/api")
public class HealthController {


@GetMapping("/api/health")
public Health ShowHealth() {
Health health = new Health("success","API is healthy");
return health;
private static final String SUCCESS_STATUS = "success";
private static final String HEALTHY_MESSAGE = "API is healthy";

/**
* Health check endpoint to verify API availability.
* @return ResponseEntity containing health status information
*/
@GetMapping("/health")
public ResponseEntity<Health> getHealthStatus() {
try {
Health health = new Health(SUCCESS_STATUS, HEALTHY_MESSAGE);
return ResponseEntity.ok(health);
} catch (Exception e) {
return ResponseEntity.internalServerError().build();
}
}

}
Loading
Loading