[JAVA] 03. I sent a request from Spring Boot to the zip code search API

Overview

You can now connect to the DB with Last time. This time, let's use RestTemplate to send a request to an external API and receive the response. The API used this time is Zip Code Search API.

What is the Zip Code Search API?

By adding query parameters to the base URL and sending It is an API that returns search results as a JSON object. For details, please refer to Link.

Let's create an API now.

Main subject

The configuration this time is a controller class that receives the zip code as a query parameter, and Let's create a client class that sends the zip code as a query parameter to the zip code search API and receives the result. (I will omit the data class) Since we will receive the zip code as an input value, we will also implement a simple validation and error handler.

1. Create Controller + Constraint

GetAddressController.java


@RestController
@RequiredArgsConstructor
@Validated  // (1)
public class GetAddressController {
    private final GetAddressApiClient client;

    @GetMapping("/get/address")
    public GetAddressResponse getAddress(@ZipCode @RequestParam("zipcode") String zipCode) {  // (1)
        return GetAddressResponse.create(client.request(zipCode));
    }
}

ZipCode.java


@Documented
@Constraint(validatedBy = {})
@Target(PARAMETER)
@Retention(RUNTIME)
@Pattern(regexp = "[0-9]{3}[-]{0,1}[0-9]{4}")  // (2)
public @interface ZipCode {
    String message() default "";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

CommonExceptionHandler.java


@RestControllerAdvice  // (3)
public class CommonExceptionHandler {

    @ExceptionHandler(ConstraintViolationException.class)  // (3)
    public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex) {
        GetAddressResponse response = new GetAddressResponse(
                "400",
                "The zip code you entered is incorrect.",
                null
        );
        return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);  // (4)
    }
}

Then, I will give a brief explanation following the last time. (1). Validation is enabled by @Validated. You can also check the validation by adding your own annotation (@ZipCode) to the query parameter, and if it violates, ConstraintViolationException will be thrown. (2). Implementation of self-made annotation. For details, please see the article here, but the validation logic is only the @ Pattern part. (3). By giving @RestControllerAdvice, you can implement the process (** AOP **) common to all controllers with @RestController. If the controller throws an exception that corresponds to the argument of @ExceptionHandler, that method will work. I think this combination is often used, so it's useful to remember. (4). The return value of the handler implemented using @ExceptionHandler should be the ResponseEntity class. It will nicely convert it to an HTTP response using the body and HTTP status given by this. By the way, you can also specify the Header attribute.

It's roughly like this. As you can see by looking at the regular expression, we have a policy that "-" may or may not be present according to the specifications of the postal code search API. Next is the Client class.

2. Make a Client

GetAddressApiClient.java


@Component
public class GetAddressApiClient {
    private final RestTemplate restTemplate;

    public GetAddressApiClient(RestTemplateBuilder restTemplateBuilder,
                               ResponseHeaderInterceptor interceptor) {  // (1)
        restTemplate = restTemplateBuilder
                .rootUri("http://zipcloud.ibsnet.co.jp")
                .additionalInterceptors(interceptor)
                .build();
    }

    public GetAddressApiResponse request(String zipCode) {
        return restTemplate.getForObject("/api/search?zipcode={zipCode}",  // (2)
                GetAddressApiResponse.class,
                zipCode);
    }
}

ResponseHeaderInterceptor.java


@Component
public class ResponseHeaderInterceptor implements ClientHttpRequestInterceptor {

    @Override  // (3)
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {
        ClientHttpResponse response = execution.execute(request, body);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        return response;
    }

}

(1). RestTeplate is initialized in the constructor. You can initialize it with each implementation method, but this time, assuming that multiple methods will be implemented, the common part will be initialized with the constructor. rootUri sets the request URI that will be the root as it is, and ʻadditionalInterceptorssets the response format. (2). An implementation method that sends a request and receives a response. Pass the request path in the first argument of thegetForObject ()method, the response class in the second argument, and the value to be mapped to the parameter in the third argument. As an implementation, this is all you need to send a request and receive a response. (3). By adding the class that implementsClientHttpRequestInterceptor to RestTemplate, you will be able to receive the response in ʻapplication / json. Please refer to here and here. * Implementation is round plagiarism.

This is all you need to do to complete the implementation. Finally, let's hit the API from Postman to see if it works as expected!

3. Try to hit it

Let's use the following 5 test patterns.

  1. Send the existing zip code (with hyphen) ⇒ You can get the address information
  2. Send the existing zip code (without hyphen) ⇒ You can get the address information
  3. Send a non-existent zip code ⇒ You can get the address information in an empty state
  4. Validation violation (insufficient number of digits) ⇒ Validation error
  5. Validation violation (multiple hyphens) ⇒ Validation error

Let's hit it.

3-1. Send an existing zip code (with hyphen) ⇒ Address information can be obtained

Result: ** OK !! ** </ font> 打鍵2.png

3-2. Send the existing zip code (without hyphen) ⇒ Address information can be obtained

Result: ** OK !! ** </ font> 打鍵1.png

3-3. Send a non-existent zip code ⇒ You can get the address information in an empty state

Result: ** OK !! ** </ font> 打鍵3.png

3-4. Validation violation (insufficient number of digits) ⇒ Validation error

Result: ** OK !! ** </ font> 打鍵4.png

3-5. Validation violation (multiple hyphens) ⇒ Validation error

Result: ** OK !! ** </ font> 打鍵5.png

It seems to be working safely! !!

Finally

You can now also send requests to external APIs! I was also able to implement a simple but simple validation check, so I think you can now create a simple API!

If you have any mistakes, we welcome your comments! Thank you for reading to the end! !!

Recommended Posts