Skip to content
Advertisement

Microservices communication with optional parameters requests

I have a room service which returns detail for rooms when requesting http://localhost:8082/room/search/byRoomChar

    @GetMapping(path = "/search/byRoomChar")
    public @ResponseBody List<Room> byCapacity(@RequestParam(required = false) Integer capacity,
                                               @RequestParam(required = false) Boolean isUnderMaintenance,
                                               @RequestParam(required = false) String equipment) {
        return roomRepository.findByRoomChar(capacity, isUnderMaintenance, equipment);
    }

Now I want to request this @GetMapping from the booking service since this is the application gateway that users are going to interact with using the http://localhost:8081/booking/search/byRoomChar.

    @GetMapping(path = "/search/byRoomChar")
    public @ResponseBody List<Room> byCapacity(@RequestParam(required = false) Integer capacity,
                                               @RequestParam(required = false) Boolean isUnderMaintenance,
                                               @RequestParam(required = false) String equipment) {
        ResponseEntity<Room[]> roomsResponse = restTemplate.getForEntity("http://localhost:8082/room/search/byRoomChar?capacity=" + capacity + "&isUnderMaintenance=" +
            isUnderMaintenance + "&equipment=" + equipment, Room[].class);
        return Arrays.asList(roomsResponse.getBody());
    }

Room entity code:

package nl.tudelft.sem.template.entities;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "Room")
public class Room {
    @EmbeddedId
    private RoomId id;

    @Column(name = "capacity")
    private int capacity;

    @Column(name = "numberOfPeople")
    private int numberOfPeople;

    @Column(name = "isUnderMaintenance", nullable = false)
    private boolean isUnderMaintenance;

    @Column(name = "equipment")
    private String equipment;

    public Room() {
    }

    public Room(long roomNumber, long buildingNumber, int capacity,
                int numberOfPeople, boolean isUnderMaintenance, String equipment) {
        RoomId id = new RoomId(roomNumber, buildingNumber);
        this.id = id;
        this.capacity = capacity;
        this.numberOfPeople = numberOfPeople;
        this.isUnderMaintenance = isUnderMaintenance;
        this.equipment = equipment;
    }

    public RoomId getId() {
        return id;
    }

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

    public int getCapacity() {
        return capacity;
    }

    public void setCapacity(int capacity) {
        this.capacity = capacity;
    }

    public int getNumberOfPeople() {
        return numberOfPeople;
    }

    public void setNumberOfPeople(int numberOfPeople) {
        this.numberOfPeople = numberOfPeople;
    }

    public boolean getIsUnderMaintenance() {
        return isUnderMaintenance;
    }

    public void setUnderMaintenance(boolean underMaintenance) {
        isUnderMaintenance = underMaintenance;
    }

    public String getEquipment() {
        return equipment;
    }

    public void setEquipment(String equipment) {
        this.equipment = equipment;
    }
}

Room repository code:

package nl.tudelft.sem.template.repositories;

import java.util.List;
import nl.tudelft.sem.template.entities.Room;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface RoomRepository extends JpaRepository<Room, Integer> {
    @Query("SELECT r FROM Room r WHERE (:number is null or r.id.number = :number)"
        + "and r.id.buildingNumber = :buildingNumber")
    List<Room> findByRoomNum(@Param("number") Long number,
                             @Param("buildingNumber") Long buildingNumber);

    @Query("SELECT r FROM Room r WHERE (:capacity is null or r.capacity = :capacity) and"
        + "(:isUnderMaintenance is null or r.isUnderMaintenance = :isUnderMaintenance) and"
        + "(:equipment is null or r.equipment = :equipment)")
    List<Room> findByRoomChar(@Param("capacity") Integer capacity,
                              @Param("isUnderMaintenance") Boolean isUnderMaintenance,
                              @Param("equipment") String equipment);

}

However, this does not work because when omitting parameters when calling the getmapping from the booking service all parameter values are turned into null because of the required=false. And this are converted into Strings inside the hard coded url.

2021-12-04 17:13:03.883  WARN 16920 --- [nio-8082-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Boolean'; nested exception is java.lang.IllegalArgumentException: Invalid boolean value [null]]

How can I make a get http request with optional parameters from within the code?

Advertisement

Answer

UriComponentsBuilder can help with URI construction. It correctly handles nullable query parameters.

String uri = UriComponentsBuilder.fromHttpUrl("http://localhost:8082/room/search/byRoomChar")
            .queryParam("capacity", capacity)
            .queryParam("isUnderMaintenance", isUnderMaintenance)
            .queryParam("equipment", equipment)
            .encode().toUriString();
ResponseEntity<Room[]> roomsResponse = restTemplate.getForEntity(uri, Room[].class);

Also, following answer can be helpful: https://stackoverflow.com/a/25434451/5990117

Advertisement