I have 2 GET endpoints for Chemical
resource:
In the first endpoint, I want the chemical object by id, which is unique through every chemical.
@GetMapping("/chemical/{id}")
In the second GET endpoint, I want all the chemicals which are correspond to a specific lab (lab is mandatory).
@GetMapping("/chemical/{labKey}")
Spring cannot distinguish between /chemical/myLab
and /chemical/12
, I can understand this. I know I should change the endpoint mapping, but how? Can someone suggest a good convention for this specific case? eg. @GetMapping("/chemical/{labKey}/{id}"
seems redundant for me, since I don't use labKey
pathVariable, I will only need id
, I will call something like this: chemicalService.findById(id)
.
CodePudding user response:
I think the best way to do this is by using two end points:
/chemical/{id}
which will fetch your chemical by identifier using@GetMapping("/chemicals/{id}")
.- The second would use a query param
labKey
to filter based on the lab key. This will have a generic@GetMapping("/chemicals")
.chemicals?labKey=lab1
would be the URI.
Below is my implementation. Controller class
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class ChemicalService {
private List<ChemicalDTO> chemicals = Arrays.asList(
new ChemicalDTO(1L, "chem1", "lab1"),
new ChemicalDTO(2L, "chem2", "lab2"),
new ChemicalDTO(3L, "chem3", "lab1"),
new ChemicalDTO(4L, "chem4", "lab3")
);
public Optional<ChemicalDTO> getChemicalById(Long id) {
return chemicals.stream().filter(e -> e.getId().equals(id)).findAny();
}
public List<ChemicalDTO> getChemicalByLabKey(String labKey) {
if( labKey.isBlank() || labKey.isEmpty() ) return new ArrayList<>();
return chemicals
.stream()
.filter(e -> e.getLabKey().equals(labKey))
.collect(Collectors.toList());
}
}
Service class
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class ChemicalService {
private List<ChemicalDTO> chemicals = Arrays.asList(
new ChemicalDTO(1L, "chem1", "lab1"),
new ChemicalDTO(2L, "chem2", "lab2"),
new ChemicalDTO(3L, "chem3", "lab1"),
new ChemicalDTO(4L, "chem4", "lab3")
);
public Optional<ChemicalDTO> getChemicalById(Long id) {
return chemicals.stream().filter(e -> e.getId().equals(id)).findAny();
}
public List<ChemicalDTO> getChemicalByLabKey(String labKey) {
if( labKey.isBlank() || labKey.isEmpty() ) return new ArrayList<>();
return chemicals
.stream()
.filter(e -> e.getLabKey().equals(labKey))
.collect(Collectors.toList());
}
}
DTO class
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class ChemicalDTO {
private Long id;
private String name;
private String labKey;
}
You can find more information in the REST resource naming conventions and examples here
CodePudding user response:
If the path is the same and the number of path variables is also the same, below would be the clean approach to handle this situation.
you can consider below code snippet
@GetMapping(value = "/chemical", params = "id")
public String getChemicalById(@RequestParam(value = "id") String id) {
return "ID method: " id;
}
@GetMapping(value = "/chemical", params = "label")
public String getChemicalByLabel(@RequestParam(value = "label") String label) {
return "Label method: " label;
}
The URLs are as follows:
- /chemical?id=ID
- /chemical?label=LABEL