7 pièce(s) jointe(s)
Spring Rest API + Docker Compose + Postgres: GET ERROR 500 AFTER POST
Bonjour à tous,
Tout est résumé dans le titre.
Je fabrique une API pour un forum de rencontres entre musiciens.
Mon projet Spring REST est basé sur celui ci:
https://spring.io/guides/tutorials/rest/
Au détail près que j'ai une base de données Postgres, et que tout est sur Docker (API + BDD) avec Docker Compose.
VOICI LA STRUCTURE DU PROJET;
Pièce jointe 611968
VOICI LE CODE POUR UNE ENTITE:
ENTITE:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
|
package com.praline40.MeetZicker.Style;
import com.praline40.MeetZicker.Group.Group;
import com.praline40.MeetZicker.Musician.Musician;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Style {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany(mappedBy = "styles")
private List<Musician> musicians = new ArrayList<>();
@ManyToMany(mappedBy = "styles")
private List<Group> groups = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<Musician> getMusicians() {
return musicians;
}
public void setMusicians(List<Musician> musicians) {
this.musicians = musicians;
}
public List<Group> getGroups() {
return groups;
}
public void setGroups(List<Group> groups) {
this.groups = groups;
}
} |
CONTROLLER:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
package com.praline40.MeetZicker.Style;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.mediatype.problem.Problem;
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.stream.Collectors;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
@RestController //Combination of @Controller and @ResponseBody. Beans returned are converted to/from JSON/XML.
public class StyleController {
//@Autowired // Autowire the StyleRepository so that we can retrieve and save data to database.
private final StyleRepository repository;
private final StyleModelAssembler assembler; // Injecting StyleModelAssembler into the controller
StyleController(StyleRepository repository, StyleModelAssembler assembler) {
this.repository = repository;
this.assembler = assembler;
}
@GetMapping("/styles/{id}")
EntityModel<Style> one(@PathVariable Long id) {
Style style = repository.findById(id) //
.orElseThrow(() -> new StyleNotFoundException(id));
return assembler.toModel(style);
}
@GetMapping("/allstyles")
public String allStyles(){
return "You wanna know all styles !!";
}
@GetMapping("/styles")
CollectionModel<EntityModel<Style>> all() {
List<EntityModel<Style>> styles = repository.findAll().stream()
.map(assembler::toModel)
.collect(Collectors.toList());
return CollectionModel.of(styles,
linkTo(methodOn(StyleController.class).all()).withSelfRel());
}
@PostMapping("/styles")
ResponseEntity<?> newStyle(@RequestBody Style newStyle) {
EntityModel<Style> entityModel = assembler.toModel(repository.save(newStyle));
return ResponseEntity //
.created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()) //
.body(entityModel);
}
@PutMapping("/styles/{id}")
ResponseEntity<?> replaceStyle(@RequestBody Style newStyle, @PathVariable Long id) {
Style updatedStyle = repository.findById(id) //
.map(style -> {
style.setName(newStyle.getName());
style.setMusicians(newStyle.getMusicians());
style.setGroups(newStyle.getGroups());
return repository.save(style);
}) // s'il n'existe pas déjà on le créé
.orElseGet(() -> {
newStyle.setId(id);
return repository.save(newStyle);
});
EntityModel<Style> entityModel = assembler.toModel(updatedStyle);
return ResponseEntity //
.created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()) //
.body(entityModel);
}
@DeleteMapping("/styles/{id}")
ResponseEntity<?> deleteStyle(@PathVariable Long id) {
repository.deleteById(id);
return ResponseEntity.noContent().build();
}
} |
ASSEMBLER:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
package com.praline40.MeetZicker.Style;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.RepresentationModelAssembler;
import org.springframework.stereotype.Component;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
@Component
public class StyleModelAssembler implements RepresentationModelAssembler<Style, EntityModel<Style>> {
@Override
public EntityModel<Style> toModel(Style style) {
return EntityModel.of(style, //
linkTo(methodOn(StyleController.class).one(style.getId())).withSelfRel(),
linkTo(methodOn(StyleController.class).all()).withRel("styles"));
}
} |
NOT FOUND EXCEPTIONS:
Code:
1 2 3 4 5 6 7 8 9
|
package com.praline40.MeetZicker.Style;
class StyleNotFoundException extends RuntimeException {
StyleNotFoundException(Long id) {
super("Could not find style " + id);
}
} |
REPOSTITORY:
Code:
1 2 3 4 5 6 7
|
package com.praline40.MeetZicker.Style;
import org.springframework.data.jpa.repository.JpaRepository;
interface StyleRepository extends JpaRepository<Style, Long> {
} |
DOCKERFILE:
Code:
1 2 3 4 5
|
FROM openjdk:11
ADD target/meetzicker.jar meetzicker.jar
ENTRYPOINT ["java", "-jar","meetzicker.jar"]
EXPOSE 8080 |
DOCKER-COMPOSE:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
version: '2.1'
services:
API:
image: 'meetzicker.jar:latest'
ports:
- "8080:8080"
depends_on:
db:
condition: service_healthy
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/${POSTGRES_DB}
- SPRING_DATASOURCE_USERNAME=${POSTGRES_USER}
- SPRING_DATASOURCE_PASSWORD=${POSTGRES_PASSWORD}
- SPRING_JPA_HIBERNATE_DDL_AUTO=update
db:
image: postgres:${POSTGRES_VERSION}
ports:
- "5432:5432"
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_DB=${POSTGRES_DB}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5 |
DANS POSTMAN:
D'abord un post qui fonctionne:
Pièce jointe 611961
Ensuite un get qui crashe:
GET http://localhost:8080/styles
Pièce jointe 611964
NB: tant que je ne fais pas de POST, le GET fonctionne (du moins pour les entités indépendantes)!
Pièce jointe 611965
Un post pour un nouvel instrument:
Pièce jointe 611966
Ensuite un get, pareil ça plante:
Pièce jointe 611967
POUR CE CONTROLLER SIMPLIFIE PAS DE SOUCIS:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
package com.praline40.MeetZicker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
@RestController //Combination of @Controller and @ResponseBody. Beans returned are converted to/from JSON/XML.
public class HomeController {
@GetMapping("/")
public String home(){
return "Welcome to Meetzicker !!";
}
} |
Pièce jointe 611969
J'y connais pas grand chose, mais comme ça je dirais que cela vient d'un soucis entre mes relations entre entitées (relations base de données). Car pourquoi cela marcherait-il tant que la base de données est vide (avant POST) ?:?
J'avoue j'y suis allé de façon un peu bourrin j'ai fait directement une architecture relationnelle poussée.
:merci: