Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1615f8e
create Word class and controller
AlbertProfe Jan 10, 2025
55f09b9
add repository and application.properties
AlbertProfe Jan 10, 2025
17056d0
create controller word method get all words
AlbertProfe Jan 10, 2025
4116bbd
spring boot rest controller docs
AlbertProfe Jan 10, 2025
8f2660e
renaming files
AlbertProfe Jan 10, 2025
5cbb18b
renaming files
AlbertProfe Jan 10, 2025
656ac27
WordController comments
AlbertProfe Jan 16, 2025
0b15c36
test with JUnit to word entity
AlbertProfe Jan 16, 2025
b5c117a
spring docs-resources images project structure
AlbertProfe Jan 16, 2025
aa68930
spring docs-resources test JUnit word
AlbertProfe Jan 16, 2025
0eb0b0f
db local
AlbertProfe Jan 17, 2025
557b0d6
new folder Test Junit
AlbertProfe Jan 17, 2025
f596df5
basic wordController CRUD
AlbertProfe Jan 17, 2025
8fd89c9
H2 local db and word controller
AlbertProfe Jan 17, 2025
8fdc1ad
move md
AlbertProfe Jan 17, 2025
6c6a27e
doc: containers and pronunciationApp-v0.1
AlbertProfe Jan 23, 2025
50b30db
feat: refactor controller and repository
AlbertProfe Jan 23, 2025
052eeef
doc: spring boot for 5yo
AlbertProfe Jan 23, 2025
bc9c5ee
fix: getWordByPhoneticSpelling at WordRepository pronunciation fields…
AlbertProfe Jan 23, 2025
c4bc3db
feat: createWords and deleteAllWords
AlbertProfe Jan 23, 2025
52be154
doc: styling docs
AlbertProfe Jan 23, 2025
04dde27
doc: annotations
AlbertProfe Jan 24, 2025
7685ec5
doc: add mock-data script
AlbertProfe Jan 24, 2025
eea3805
doc: image h2 with mock data
AlbertProfe Jan 24, 2025
90e659a
feat: refactor with ResponseEntity, headers and optional
AlbertProfe Jan 24, 2025
ec64ac1
doc: import .csv to H2 DB
AlbertProfe Jan 24, 2025
bc73644
feat: complete user CRUD with validation
bielidev Feb 2, 2025
ba7fa58
modify gitignore
bielidev Feb 2, 2025
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.DS_Store
.idea
pronunciationDB
53 changes: 53 additions & 0 deletions backend/pronunciationAppBack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
## Descripción
Este PR implementa la gestión de usuarios en una aplicación **Spring Boot**, cumpliendo con los siguientes requisitos:

1. **Crear la entidad User**
- Se ha diseñado una entidad de usuario con los campos relevantes.
- Se han añadido anotaciones de **JPA** para la persistencia.
- Se han implementado **validaciones** con `@Id , @NotNull`, `@Email`, `@Min(18)`.

2. **Desarrollar UserController**
- Se han creado **endpoints RESTful** para la gestión de usuarios.
- Se ha añadido **manejo de errores** apropiado.
- Se ha utilizado `ResponseEntity` para respuestas flexibles.

3. **Implementar UserRepository**
- Se ha extendido `JpaRepository`.
- Se ha asegurado una correcta interacción con la base de datos.

4. **Configurar la base de datos H2**
- Se ha configurado **`application.properties`** para usar H2 en local.
- Se han definido los parámetros de conexión.
- Se ha habilitado la **consola H2** para desarrollo.

5. **Desarrollar UserService**
- Se ha implementado la **lógica de negocio** para operaciones con usuarios.
- Se ha agregado una capa de servicio entre el controlador y el repositorio.
- Se ha incluido **validación y transformación de datos**.

6. **Pruebas con Postman**
- Se ha creado una colección de pruebas para los **endpoints de usuario**.
- Se han probado todas las operaciones **CRUD**.
- Se ha verificado la **integridad de los datos y códigos de respuesta**.

---

## Capturas

### **Pruebas en Postman**
Se han ejecutado y validado las peticiones.
>️ **Obener los usuarios**
![Get all users](screenshots/getallusers.png)
> **Obener usuario por id**
![Get user by id](screenshots/getuserbyid.png)
> **Crear usuario**
![Create user](screenshots/createuser.png)
> **Actualizar usuario**
![Update user](screenshots/updateuser.png)
> **Eliminar usuario**
![Delete user](screenshots/deleteuser.png)

### 🛢️ **Base de Datos H2 en el Navegador**
Se ha verificado la persistencia de los datos en H2.

![BD H2 en navegador](screenshots/bdh2.png)
9 changes: 9 additions & 0 deletions backend/pronunciationAppBack/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
Expand Down Expand Up @@ -65,6 +70,10 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Binary file added backend/pronunciationAppBack/screenshots/bdh2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package dev.pronunciationAppBack.controller;

import dev.pronunciationAppBack.model.User;
import dev.pronunciationAppBack.model.Word;
import dev.pronunciationAppBack.service.UserService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/api/users")
public class UserController {

@Autowired
UserService userService;

@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
return new ResponseEntity<>(userService.getAllUsers(), getCommonHeaders(), HttpStatus.OK);
}

@GetMapping("/{id}")
public ResponseEntity<User> getById(@PathVariable String id) {
Optional<User> user = userService.getById(id);
HttpHeaders headers = getCommonHeaders();

return user.map(value -> new ResponseEntity<>(value, headers, HttpStatus.OK))
.orElseGet(() -> new ResponseEntity<>(headers, HttpStatus.NOT_FOUND));
}

@PostMapping("/create")
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
Optional<User> created = userService.createUser(user);

HttpHeaders headers = getCommonHeaders();

return created.map(value -> new ResponseEntity<>(value, headers, HttpStatus.OK))
.orElseGet(() -> new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST));
}

@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable String id, @Valid @RequestBody User user) {
Optional<User> edited = userService.updateUser(id, user);

HttpHeaders headers = getCommonHeaders();

return edited.map(value -> new ResponseEntity<>(value, headers, HttpStatus.OK))
.orElseGet(() -> new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST));
}

@DeleteMapping("/{id}")
public ResponseEntity<String> deleteUser(@PathVariable("id") String idToDelete) {
Optional<String> msg = userService.deleteUser(idToDelete);

HttpHeaders headers = getCommonHeaders();

return msg.map(value -> new ResponseEntity<>(value, headers, HttpStatus.OK))
.orElseGet(() -> new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST));
}

private HttpHeaders getCommonHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.add("content-type", "application/json");
return headers;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package dev.pronunciationAppBack.controller;

import dev.pronunciationAppBack.model.Word;
import dev.pronunciationAppBack.repository.WordRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/api/words")
public class WordController {

@Autowired
private WordRepository wordRepository;

@GetMapping("/hello")
public ResponseEntity<String> hello() {
HttpHeaders headers = getCommonHeaders("Hello endpoint");
return new ResponseEntity<>("hello Emiliano, are you sleeping?", headers, HttpStatus.OK);
}

@GetMapping
public ResponseEntity<List<Word>> getAllWords() {
List<Word> words = wordRepository.findAll();
HttpHeaders headers = getCommonHeaders("Get all words");

return !words.isEmpty()
? new ResponseEntity<>(words, headers, HttpStatus.OK)
: new ResponseEntity<>(headers, HttpStatus.NOT_FOUND);
}

@GetMapping("/{id}")
public ResponseEntity<Word> getWordById(@PathVariable String id) {
Optional<Word> word = Optional.ofNullable(wordRepository.getWordById(id));
HttpHeaders headers = getCommonHeaders("Get word by ID");

return word.map(value -> new ResponseEntity<>(value, headers, HttpStatus.OK))
.orElseGet(() -> new ResponseEntity<>(headers, HttpStatus.NOT_FOUND));
}

@PostMapping("/createWord")
public ResponseEntity<Word> createWord(@RequestBody Word word) {
Word createdWord = wordRepository.save(word);
HttpHeaders headers = getCommonHeaders("Create a new word");

return new ResponseEntity<>(createdWord, headers, HttpStatus.CREATED);
}

@PutMapping("/{id}")
public ResponseEntity<Word> updateWord(@PathVariable String id, @RequestBody Word word) {
Word updatedWord = wordRepository.save(word);
HttpHeaders headers = getCommonHeaders("Update a word");

return new ResponseEntity<>(updatedWord, headers, HttpStatus.OK);
}

@DeleteMapping("/{id}")
public ResponseEntity<String> deleteWord(@PathVariable("id") String idToDelete) {
HttpHeaders headers = getCommonHeaders("Delete a word");

if (wordRepository.existsById(idToDelete)) {
wordRepository.deleteById(idToDelete);
return new ResponseEntity<>("Word deleted", headers, HttpStatus.OK);
} else {
return new ResponseEntity<>("Word not found", headers, HttpStatus.NOT_FOUND);
}
}

@DeleteMapping
public ResponseEntity<String> deleteAllWords() {
wordRepository.deleteAll();
HttpHeaders headers = getCommonHeaders("Delete all words");
return new ResponseEntity<>("All words deleted", headers, HttpStatus.OK);
}

private HttpHeaders getCommonHeaders(String description) {
HttpHeaders headers = new HttpHeaders();
headers.add("desc", description);
headers.add("content-type", "application/json");
headers.add("date", new Date().toString());
headers.add("server", "Spring Boot");
headers.add("version", "1.0.0");
headers.add("word-count", String.valueOf(wordRepository.count()));
headers.add("object", "words");
return headers;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package dev.pronunciationAppBack.model;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;

@Entity
public class User {

@Id
private String id;
@NotNull
private String userName;
@NotNull
private String firstName;
private String lastName;
@NotNull
@Email
private String email;
private boolean isActive;
@Min(18)
private int age;

public User(String id, String userName, String firstName, String lastName, String email, boolean isActive, int age) {
this.id = id;
this.userName = userName;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.isActive = isActive;
this.age = age;
}

public User() {

}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public boolean isActive() {
return isActive;
}

public void setActive(boolean active) {
isActive = active;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", userName='" + userName + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", isActive=" + isActive +
", age=" + age +
'}';
}
}
Loading