2

I am trying to get a JSON Object from an API while using an API key in the header. This works perfectly when I test it in Postman, but when I try it in my Spring application.

I got an error:

There was an unexpected error (type=Not Found, status=404). No message available.

API-Key and the URL are changed out with dummy data

@RequestMapping(value = "/apitest", method = RequestMethod.GET, headers ="APIKey=12345")
public @ResponseBody void testingAPI() throws ParseException {

final RestTemplate restTemplate = new RestTemplate();
final String response = restTemplate.getForObject("url", String.class);
System.out.println(response);
}
imkepo
  • 135
  • 1
  • 1
  • 10
  • 1
    What is the point of having `@ResponseBody` if you return nothing? Also, are you sure you make the request with `APIKey=12345` header? –  Jul 24 '19 at 08:20
  • Im going to modify the json i receive and return something, but at this point I can't get the json data. You think the header is the problem? – imkepo Jul 24 '19 at 08:22
  • 1
    So it doesn't even enter the `testingAPI()` method? –  Jul 24 '19 at 08:24
  • No I don't think it does, since the print isn't being called. – imkepo Jul 24 '19 at 08:24
  • 1
    Using `consumes = application/json` assumes that you are passing JSON data as input in your method, that's why you got the error `Content type not supported` as you don't have any input param in your method. – cнŝdk Jul 24 '19 at 08:29
  • 1
    How are you calling the API in your Spring application? Are you sure you are using the right config? – cнŝdk Jul 24 '19 at 08:36
  • 1
    I've used this method to get json from other API's in the same application, only difference is in this one I had to use an API key. It worked fine on the others. – imkepo Jul 24 '19 at 08:39
  • So this means the header is not correctly passed, I'd recommend using [`@RequestHeader` annotation](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestHeader.html) to handle your API KEY. – cнŝdk Jul 24 '19 at 08:44

3 Answers3

2

If your are testing your API in Postman and it works perfectly, and in your application it's not working, this means that your method mapping isn't correct or it's not correctly called.

But from the comments where you said that the same configuration works if you don't have an API key, this means that your header isn't correctly mapped, in this case I'd recommend using @RequestHeader annotation to handle your API key.

Your method mapping will be like this:

@RequestMapping(value = "/apitest", method = RequestMethod.GET)
public @ResponseBody void testingAPI(@RequestHeader("APIKey") String apiKey) throws ParseException {
    final RestTemplate restTemplate = new RestTemplate();
    final String response = restTemplate.getForObject("url", String.class);
    System.out.println(response);
}

If you want to use 12345 as a default value for your API key param you can write:

@RequestMapping(value = "/apitest", method = RequestMethod.GET)
public @ResponseBody void testingAPI(@RequestHeader(name = "APIKey", defaultValue = "12345") String apiKey) throws ParseException {

You can check How to Read HTTP Headers in Spring REST Controllers tutorial for further reading about the @RequestHeader annotation.

cнŝdk
  • 31,391
  • 7
  • 56
  • 78
  • Your method is not equivalent to the OP's method, since it is called for **every** APIKey value, not only for `12345` –  Jul 24 '19 at 09:18
  • 1
    @EugenCovaci It's a param, you can pass whatever you want, when it's called we can simply pass `12345` or even better we can use a default value like `@RequestHeader(name = "APIKey", defaultValue = "12345")`, this is how it should be done. – cнŝdk Jul 24 '19 at 09:25
  • I tried using your example with the 12345 as default but it is giving me an error: (type=Internal server error, status=500). 401 Access Denied – imkepo Jul 24 '19 at 10:15
  • So it seems like the API key still isn't passed correctly? – imkepo Jul 24 '19 at 10:22
  • Yes, this means the APIKey isn't correctly mapped, can you edit your Original Post with a screenshot of your Postman config and how are you calling the method in the code? – cнŝdk Jul 24 '19 at 10:28
  • I've edited the post now with three screenshots. Obviously the key is dummy data and not the real key. The method is being called when i access my local URL for localhost:5012/apitest – imkepo Jul 24 '19 at 10:43
  • @imkepo If you are calling the api from the url in the browser, then the header won't be set, so you need to define the header param as optional. You can use the following `required = false`, so it would be: `@RequestHeader(value = "APIKey", defaultValue = "12345", required = false)`. – cнŝdk Jul 24 '19 at 10:50
  • Did the change, but still getting 401 Access Denied. – imkepo Jul 24 '19 at 10:56
  • But why are you using the 2 params in Postman (`vesselimo` and `output`), you haven't mapped any of them? And if you are using them in Postman, you should also pass them in the url of your browser. – cнŝdk Jul 24 '19 at 11:08
  • They get added automatically in postman when i add "vesselimo=8505941&output=json" in the url. So I just added them in my final URL in the method, in the getForObject instead of adding them as parameters. But this shouldn't affect me getting access denied? – imkepo Jul 24 '19 at 11:11
  • Im getting inside my method now with your code, which I didnt do with my original code. If I call a print before the restTemplate, it will print it now. – imkepo Jul 24 '19 at 11:13
  • So in this case, the problem isn't with the method, it seems to be something with `restTemplate.getForObject("url", String.class)`. – cнŝdk Jul 24 '19 at 11:17
  • I added two screenshots from the console I get when trying to access the method. The "hello world" print at the top is the print I printed right above the restTemplate. – imkepo Jul 24 '19 at 11:26
  • You should edit the method to pass the header param along with the params in the url, so you can access the inner request; – cнŝdk Jul 24 '19 at 11:38
  • I've added a new screenshot from my code under "Actual configuration", where i use params in the url. But how do i apply these to my resttemplate? Currently im just printing them out before accessing the resttemplate and still getting the 401 Access Denied. – imkepo Jul 25 '19 at 08:06
  • @imkepo Well you need to pass them through `RestTemplate`, take a look at [this code snippet](https://stackoverflow.com/a/25434451/3669624). – cнŝdk Jul 26 '19 at 15:17
0

A quick fix could be to change the void to a Class. like

@RequestMapping(value = "/apitest", method = RequestMethod.GET, headers ="APIKey=12345")
@ResponseBody 
public XXXResponse testingAPI() throws ParseException {
   ...
   return new XXXRepsonse();
}

or:

@RequestMapping(value = "/apitest", method = RequestMethod.GET, headers ="APIKey=12345")
public void testingAPI() throws ParseException {
   ...
}
0

Where are you add header in your request? You controller should look like this:

@RestController
public class DemoController {
@GetMapping("/apitest" )
public void doRequest(@RequestHeader(name = "Ocp-Apim-Subscription-Key", defaultValue = "12345") String apiKey) {
    RestTemplate restTemplate = new RestTemplate();

    MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    headers.add("Ocp-Apim-Subscription-Key", apiKey);

    ResponseEntity<String> responseEntity = restTemplate.exchange("https://api.kognif.ai/AIS/v1/aispositioncurrent?vesselimo=8505941&output=json",
            HttpMethod.GET, new HttpEntity<String>(headers), String.class);

    System.out.println(responseEntity.toString());
}
}

Postman request to your Spring app must be : enter image description here

And of course, specify valid Ocp-Apim-Subscription-Key

Valeriy K.
  • 2,616
  • 1
  • 30
  • 53