Im currently trying to perform a GET method on my "Courses" microservice controller. But when i try to fetch i get a 405 error code.
The general idea is that i perform a GET on the "Courses" microservice to get objects by id from the "Purchases" microservice.
Feign class in the purchases where im performing a GET
#FeignClient(value = "COURSES", configuration = {
FeignConfig.class
})
public interface CourseService {
#GetMapping("/courses/all-by-id")
CoursesByIdResponse getAllByCourseIds(#RequestBody CourseIdsRequest courseIds);
}
Course Controller
#RestController()
#CrossOrigin(origins = "*", maxAge = 3600)
public class CourseController {
private final CoursePaginatedService courseService;
public CourseController(#Qualifier("paginatedService") CoursePaginatedService courseService) {
this.courseService = courseService;
}
#GetMapping("/courses/all-by-id")
public ResponseEntity<CoursesByIdResponse> getAllByCourseIds(#RequestBody CourseIdsRequest courseIds){
return ResponseEntity.ok(courseService.getAllByCourseIds(courseIds.getCourseIds()));
}
}
I have more methods in the Course controller that work propperly (200 ok).
#GetMapping("/courses/course/{id}")
public ResponseEntity<CourseByIdResponse> getCourseById(#PathVariable(value = "id") Long id){
return ResponseEntity.ok(courseService.getCourseById(id));
}
My Request and response classes.
#Data
#AllArgsConstructor
#NoArgsConstructor
public class CourseIdsRequest {
private List<Long> courseIds;
}
#AllArgsConstructor
#NoArgsConstructor
#Data
public class CoursesByIdResponse {
List<Course> courses;
}
I have no idea what it could be.
Related
I have created two microservices - Microservice 1 and Microservice 2.
Microservice 2 - Returns List of TrainDetailsToReturn(object) running on a specific date and between two cities.
Microservice 1 - Consumes Microservice 2 and returns the same List of TrainDetailsToReturn.
From Microservice 2
Controller -
#RestController
#RequestMapping("/api/v1/")
public class TrainDetailsController {
#Autowired
private TrainServices trainServices;
#PostMapping("get-train-details")
public ListOfTrainDetailsToReturn trainDetails(#RequestBody AvailableTrainDTO availableTrainDTO) throws Exception {
return trainServices.getTrainDetails(availableTrainDTO);
}
Class - ListOfTrainDetailsToReturn
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class ListOfTrainDetailsToReturn {
List<TrainDetailsToReturn> list;
}
Class - TrainDetailsToReturn
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode
public class TrainDetailsToReturn {
private long trainId;
private String trainName;
private String source;
private int sourceDepartureTime;
private String destination;
private int destinationArrivalTime;
private int fare;
}
Class - AvailableTrainDTO
#Getter
#Setter
#AllArgsConstructor
#EqualsAndHashCode
#NoArgsConstructor
public class AvailableTrainDTO {
private long source_id;
private long destination_id;
private String date;
}
Microservice 1
Controller-
#RestController
#RequestMapping("/getavailabletrains")
public class TrainController {
#Autowired
private RestTemplate restTemplate;
//we take two stations and date as input and get a list of trains along with their details from the train-details
//microservice
#GetMapping
public String betweenCities(){
return "Enter source and destination along with date ";
}
#PostMapping
public ListOfTrainDetailsToReturn availableTrains(#RequestBody AvailableTrainDTO availableTrainDTO){
ListOfTrainDetailsToReturn list = restTemplate
.postForObject("http://localhost:8080/api/v1/get-train-details" ,
availableTrainDTO ,
ListOfTrainDetailsToReturn.class );
return list;
}
}
Class - ListOfTrainDetailsToReturn
import lombok.*;
import java.util.List;
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class ListOfTrainDetailsToReturn {
List<TrainDetailsToReturn> list;
public void setList(List<TrainDetailsToReturn> list) {
this.list = list;
}
public List<TrainDetailsToReturn> get
}
Class - TrainDetailsToReturn
import lombok.*;
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode
public class TrainDetailsToReturn {
private long trainId;
private String trainName;
private String source;
private int sourceDepartureTime;
private String destination;
private int destinationArrivalTime;
private int fare;
}
Response from Microservice 2 to Post Request from Postman -
Request
{
"source_id":"100",
"destination_id":"140",
"date": "05/09/2022"
}
Response
{
"list": [
{
"trainId": 12018,
"trainName": "Dehradun Shatabdi Express",
"source": "Saharanpur",
"sourceDepartureTime": 1015,
"destination": "Bangalore",
"destinationArrivalTime": 1800,
"fare": 50
}
]
}
Response from Microservice to Post Request from Postman -
Request
{
"source_id":"100",
"destination_id":"140",
"date": "05/09/2022"
}
Response
{
"list": []
}
I have watched a few Youtube videos but can't really find a solution.
Before trying to answer your question, I suggest you to read this post on how to name your REST resources : https://restfulapi.net/resource-naming/ .
I guess, some PostMapping you did should be a GetMapping instead (#PostMapping("get-train-details")).
Last things, I suggest you to look at feign library if you don't know it. You could replace this old RestTemplate :) https://www.baeldung.com/intro-to-feign
So for your issue, have you try to put a breakpoint on your microservice 2 when microservice 1 calling it ? To see what do you have on input/output.
#PostMapping("get-train-details")
public ListOfTrainDetailsToReturn trainDetails(#RequestBody AvailableTrainDTO availableTrainDTO) throws Exception {
return trainServices.getTrainDetails(availableTrainDTO); // breakpoint here
}
Could you post the full requests from your postman ?
I have two API:s , CarRental-API on port 8080 and CarRental-CRUD on port 8081.
CarRental-CRUD uses JpaRepository to access a h2 memory DB.
I want to use CarRental-API to make requests to CarRental-CRUD, using webclient.
In CarRental-CRUD , I can make post requests and add cars to the db using this service:
public String addCar(Car car) {
carRepository.save(car);
return loggerService.writeLoggerMsg("CREATED CAR AND ADDED TO DB");
}
And then in the controller :
#RestController
#RequestMapping("/crud/v1")
public class AdminCarController {
#Autowired
private AdminCarService adminCarService;
#PostMapping(path = "/addcar", consumes = "application/json")
public String addCar(#RequestBody Car car) {
return adminCarService.addCar(car);
}
}
I tried to post a request with webclient in CarRental-API with :
#Service
public class AdminCarService {
#Autowired
LoggerService loggerService;
#Autowired
private WebClient.Builder webClientBuilder;
public String addCar(Car car) {
webClientBuilder
.build()
.post()
.uri("localhost:8081/crud/v1/addcar")
.retrieve()
.bodyToFlux(Car.class);
return loggerService.writeLoggerMsg("ADDED CAR TO DB");
}
}
However, using the carRental-API , I get this error in postman when I try to post a request :
"status": 500,
"error": "Internal Server Error",
"trace": "org.springframework.web.reactive.function.client.WebClientResponseException: 200 OK from POST localhost:8081/crud/v1/addcar; nested exception is org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'text/plain;charset=UTF-8' not supported for bodyType=com.backend.carrentalapi.entity.Car\n\tat
This is the Car Entity :
#Getter
#Setter
#RequiredArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "TBL_CAR")
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long carId;
#Column(name = "NAME")
private String carName;
#Column(name = "MODEL")
private String carModel;
#Column(name = "DAILY_PRICE")
private double dailyPrice;
}
I can't seem to find where in the code I am producing text/plain. I made sure in postman that I'm posting a raw JSON body request, and the headers say content type : application/json.
In your WebClient you are not adding the request body, but instead expecting a Car back from the API you are calling (and this API returns a simple String instead). The following should work.
#Service
public class AdminCarService {
#Autowired
LoggerService loggerService;
#Autowired
private WebClient.Builder webClientBuilder;
public String addCar(Car car) {
webClientBuilder
.build()
.post()
.uri("localhost:8081/crud/v1/addcar")
.body(BodyInserters.fromValue(car))
.retrieve()
.toBodilessEntity();
return loggerService.writeLoggerMsg("ADDED CAR TO DB");
}
}
Using .toBodilessEntity() since you don't really do anything with the response.
I am currently setting up a Rest API server using Spring Boot (v2.5.5), Spring Data Couchbase (v4.2.5) and Couchbase (v6.6.1).
I get a really strange behavior when requesting
count() -> 0
findAll() -> []
Whereas
findById() is returning a result.
My entity:
{"mkey": { "keyContent": "AA", "mkeyStatus": "L" }, "sequences": [ { "direction": "B", "loc1Value": "NCE", "loc2Value": "NYC" } ] }
#Document #Data #AllArgsConstructor #NoArgsConstructor #EqualsAndHashCode public class AirlineProfile {
#Id private String id;
#Field private MKey mkey;
#Field private List<Sequence> sequences;
#EqualsAndHashCode #AllArgsConstructor #NoArgsConstructor #Data static class MKey {
#Field private String keyContent;
#Field private String mkeyStatus;
}
#EqualsAndHashCode #AllArgsConstructor #NoArgsConstructor #Data static class Sequence {
#Field private String loc1Value;
#Field private String loc2Value;
#Field private String direction;
}
}
My repository is extending the CrudRepository.
public interface AirlineProfileRepository extends CrudRepository<AirlineProfile, String> {}
While my Service is the following:
#Service #Qualifier("AirlineProfileServiceImpl") public class AirlineProfileServiceImpl
implements AirlineProfileService {
#Autowired private AirlineProfileRepository airlineProfileRepository;
#Override
public long count() {
return airlineProfileRepository.count();
}
#Override
public List<AirlineProfile> findAll() {
List<AirlineProfile> airlineProfiles = new ArrayList<>();
for (AirlineProfile airlineProfile : airlineProfileRepository.findAll()) {
airlineProfiles.add(airlineProfile);
}
return airlineProfiles;
}
#Override public AirlineProfile findById(String id) {
return airlineProfileRepository.findById(id).orElse(null);
}
}
And my controller the following:
#RestController #RequestMapping("/api") public class AirlineProfileController {
#Autowired AirlineProfileService airlineProfileService;
#GetMapping("/airlineprofile/count") public long count() {
System.out.println("Count");
return airlineProfileService.count();
}
#GetMapping("/airlineprofile/all") public List<AirlineProfile> getAllAirlineProfiles() {
System.out.println("Get all AirlineProfile");
return airlineProfileService.findAll();
}
#GetMapping("/airlineprofile/id={id}") public AirlineProfile getAirlineProfileById(#PathVariable String id) {
System.out.println("Get AirlineProfile for id = " + id);
return airlineProfileService.findById(id);
}
}
I do not know if I missed something at Server or Couchbase side ... :(
Thank you for your help!
Ok, found that:
public interface AirlineProfileRepository extends CrudRepository<AirlineProfile, String> {
#Query("#{#n1ql.selectEntity}")
List<AirlineProfile> findAll();
}
Is working ...
So, I am questioning myself about the usability of findAll() ...
I'm learning Spring with JPA. I created a local DB with MySQL storing "Users", a web service with Spring and a front with angular.
I fed some data to my DB, and managed to display it with Angular. But the Post request coming from the Angular form does not seems to work. The form works well and provide an Object.
User model:
#Entity
#Table(name = "utilisateur")
public class Utilisateur {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String firstname;
private String lastname;
private int age;
DAOuser :
#Repository
public interface DAOutilisateur extends JpaRepository<Utilisateur, Integer> {
}
UserController :
#RestController
#CrossOrigin(origins = "http://localhost:4200")
public class UtilisateurController {
DAOutilisateur utilisateurDAO;
#Autowired
public UtilisateurController(final DAOutilisateur utilisateurDAO) {
this.utilisateurDAO = utilisateurDAO;
}
#GetMapping({"/listeUtilisateur"})
public List<Utilisateur> listUtilisateur(){
System.out.println("Liste des utilisateurs");
return utilisateurDAO.findAll();
}
#PostMapping("/listeUtilisateur")
void addUser(#RequestBody Utilisateur user) {
System.out.println("ECHO");
utilisateurDAO.save(user);
}
}
TypeScript Fonction used in Angular to access the Post URL, User is an Object created via an Form:
public saveUserSpring(user: UserSpring) {
return this.http.post<UserSpring>(this.userUrl, user);
}
Thank you for your Help !
Bertrand
Solved
As Rohit Kavathekar mentioned above, I didn't subscribed to the .post method in my angular project, which return an Observable and required to be subscribed.
Thank you.
can anyone help me how can I wrap multiple strings into a single string in postman and call spring boot rest API.
from postman I am calling my rest API via GET request
localhost:8084/restapi/v1?searchRequest= {"userId":"value1","userGroup":"value2","staus":"value2"}
here inside searchRequest I would like to wrap "userId","userGroup" and "status" with values to call my spring boot rest API Get request. and in my service class I am trying to covert this string to DTO but it is not converting, here is my code in the controller, service layer, util class
Controller:
#Autowired
private UserUtility userUtility;
#GetMapping(path = "/restapi/v1", consumes = "text/plain")
public UserInfoDetails searchUserDetails(#RequestParam String searchRequest) {
UserInfoDetails userInfoDetails = new UserInfoDetails();
try {
userUtility.searchUserDetails(searchRequest);
} catch (Exception e) {
e.printStackTrace();
}
return userInfoDetails;
}
Util class
#Autowired
private ModelMapper mapper;
public UserInfoDetails searchUserDetails(String searchRequest) {
UserInfoDetails userInfoDetails = new UserInfoDetails ();
try {
SearchRequest SearchRequest =mapper.map(searchRequest, SearchRequest.class);
//some business logic and assign the details to userInfoDetails
} catch (Exception e) {
e.printStackTrace();
}
return userInfoDetails ;
}
Search Request class
#Getter
#Setter
#NoArgsConstructor
#ToString
public class SearchRequest {
private String userId;
private String userGroup;
private String status;
}
i tried multiple ways but could not succeed, any suggestions would be really appreciated.
I would suggest to pass all the parameters as RequestParam and them bind them to object directly
Request :
localhost:8084/restapi/v1?userId=value1,userGroup=value2,staus=value3
POJO :
#Getter
#Setter
#NoArgsConstructor
#ToString
public class SearchRequest {
private String userId;
private String userGroup;
private String status;
}
Controller :
#GetMapping(path = "/restapi/v1", consumes = "text/plain")
public UserInfoDetails searchUserDetails(SearchRequest searchRequest){
//some code
}