Avi
Avi

Reputation: 21866

Feign client mapping by parameter

I have a feign client that looks something like that:

@RequestMapping(method = RequestMethod.POST, value = "/breakdowns/utmMedium", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
List<Breakdown> getUtmMediumBreakdowns(
    @RequestBody Record record,
    @RequestParam("since") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime since,
    @RequestParam("until") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime until,
    @RequestParam("timezone") String timezone
);


@RequestMapping(method = RequestMethod.POST, value = "/breakdowns/utmCampaign", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
List<Breakdown> getUtmCampaignBreakdowns(
    @RequestBody Record record,
    @RequestParam("since") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime since,
    @RequestParam("until") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime until,
    @RequestParam("timezone") String timezone
);


@RequestMapping(method = RequestMethod.POST, value = "/breakdowns/utmSource", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
List<Breakdown> getUtmSourceBreakdowns(
    @RequestBody Record record,
    @RequestParam("since") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime since,
    @RequestParam("until") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime until,
    @RequestParam("timezone") String timezone
);

As you can see, the three methods are exactly the same aside for the difference in the API path that changes according to the parameter utmMedium, utmCampaign and utmSource as in the server side we do treat those differently.

I can't change the server so I can't change the endpoint to accept this parameter as a request param or something. I wonder if there is a way for me to still parameterize this part of the path so I'd have only a single method instead of three.

Upvotes: 0

Views: 24034

Answers (2)

gbarco
gbarco

Reputation: 159

If you want to add compile time checks to the alternative URIs, a String Enum can be used for the utmType parameter. This assumes you are using Spring Open Feign. Plain Feign would require alternate annotations some starting guidance for that case can be found here.:

//Slight changes should be introduced in the getUtmCampaignBreakdowns method signature utmType parameter.
package test;

import java.time.ZonedDateTime;
import java.util.List;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "utmThing", url = "${feign.client.config.utmThing.url}")
public interface Test {
  @PostMapping(value = "/breakdowns/{utmType}", consumes = MediaType.APPLICATION_JSON_VALUE)
  List<Breakdown> getUtmCampaignBreakdowns(
      @RequestBody Record record,
      @PathVariable("utmType") UtmTypes utmType, //<-Type changed to Enum
      @RequestParam("since") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime since,
      @RequestParam("until") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime until,
      @RequestParam("timezone") String timezone
  );
}


//An enum should be declared
package test;

enum UtmTypes {
  UTM_MEDIUM("utmMedium"),
  UTM_CAMPAIGN("utmCampaign"),
  UTM_SOURCE("utmSource");

  private final String utmType;

  UtmTypes(String utmType) {
        this.utmType = utmType;
  }

  //Do not forget to privide a toString() that would map to the URI parameter
  public String toString() {
    return utmType;
  }
}

//Can be used like so:
package test;

import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.TimeZone;
import org.springframework.beans.factory.annotation.Autowired;

public class User {

  @Autowired
  void User(Test test) {
    test.getUtmCampaignBreakdowns(new Record(), UtmTypes.UTM_CAMPAIGN, ZonedDateTime.now(),
        ZonedDateTime.now().plusDays(1),
        Arrays.stream(TimeZone.getAvailableIDs())
            .filter(zoneName -> zoneName.contains("Montevideo")).findFirst()
            .orElse(TimeZone.getAvailableIDs()[0]));
  }
}

//Assuming simple Record and Breakdown implementations
package test;

public class Record {
  private String someField;

  public void setSomeField(String someField) {
    this.someField = someField;
  }

  public String getSomeField() {
    return this.someField;
  }
}

package test;

public class Record {
  private String someField;

  Record() {
    this.someField = "defaultValue";
  }

  public void setSomeField(String someField) {
    this.someField = someField;
  }

  public String getSomeField() {
    return this.someField;
  }
}

Upvotes: 0

yongsung.yoon
yongsung.yoon

Reputation: 5589

You can define additional parameter with @PathVariable annotation like the below utmType.

@RequestMapping(method = RequestMethod.POST, value = "/breakdowns/{utmType}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
List<Breakdown> getUtmCampaignBreakdowns(
    @RequestBody Record record,
    @PathVariable("utmType") String utmType,
    @RequestParam("since") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime since,
    @RequestParam("until") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime until,
    @RequestParam("timezone") String timezone
);

One thing that you have to be careful about is that you need to specify the name utmType like @PathVariable("utmType") with annotation.

Upvotes: 3

Related Questions