A API de registro se torna RESTful

A API de registro se torna RESTful

1. Visão geral

Nos últimos artigos dethe Registration series here on example, construímos a maioria das funcionalidades de que precisávamos em um estilo MVC.

Agora vamos fazer a transição de algumas dessas APIs para uma abordagem mais RESTful.

2. A operação deRegister

Vamos começar com a operação principal do Registro:

@RequestMapping(value = "/user/registration", method = RequestMethod.POST)
@ResponseBody
public GenericResponse registerUserAccount(
      @Valid UserDto accountDto, HttpServletRequest request) {
    logger.debug("Registering user account with information: {}", accountDto);
    User registered = createUserAccount(accountDto);
    if (registered == null) {
        throw new UserAlreadyExistException();
    }
    String appUrl = "http://" + request.getServerName() + ":" +
      request.getServerPort() + request.getContextPath();

    eventPublisher.publishEvent(
      new OnRegistrationCompleteEvent(registered, request.getLocale(), appUrl));

    return new GenericResponse("success");
}

Então - como essa forma é diferente da implementação original focada no MVC?

Aqui vai:

  • a solicitação agora está mapeada corretamente para um HTTP POST

  • agora estamos retornando um DTO adequado e organizando-o por meio da anotação@ResponseBody diretamente no corpo da Resposta

  • não estamos mais lidando com tratamento de erros no método

Também estamos removendo o antigoshowRegistrationPage() - já que não é necessário simplesmente exibir a página de registro.

4. Manipulação de exceção

Juntamente com a API mais RESTful, a lógica de manipulação de exceções também se tornará mais madura.

Estamos usando o mesmo mecanismo@ControllerAdvice para lidar de forma limpa com as exceções lançadas pelo aplicativo - e agora precisamos de um novo tipo de exceção.

Este é oBindException - que é lançado quandoUserDto é validado (se inválido). Iremos substituir o métodoResponseEntityExceptionHandler padrãohandleBindException() para adicionar os erros no corpo da resposta:

@Override
protected ResponseEntity handleBindException
  (BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
    logger.error("400 Status Code", ex);
    BindingResult result = ex.getBindingResult();
    GenericResponse bodyOfResponse =
      new GenericResponse(result.getFieldErrors(), result.getGlobalErrors());

    return handleExceptionInternal(
      ex, bodyOfResponse, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
}


Também precisaremos lidar com nossoExceptionUserAlreadyExistException personalizado - que é acionado quando o usuário se registra com um e-mail já existente:

@ExceptionHandler({ UserAlreadyExistException.class })
public ResponseEntity handleUserAlreadyExist(RuntimeException ex, WebRequest request) {
    logger.error("409 Status Code", ex);
    GenericResponse bodyOfResponse = new GenericResponse(
      messages.getMessage("message.regError", null, request.getLocale()), "UserAlreadyExist");

    return handleExceptionInternal(
      ex, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);
}




5. OGenericResponse

Também precisamos melhorar a implementação deGenericResponse para conter esses erros de validação:

public class GenericResponse {

    public GenericResponse(List fieldErrors, List globalErrors) {
        super();
        ObjectMapper mapper = new ObjectMapper();
        try {
            this.message = mapper.writeValueAsString(fieldErrors);
            this.error = mapper.writeValueAsString(globalErrors);
        } catch (JsonProcessingException e) {
            this.message = "";
            this.error = "";
        }
    }
}

6. UI - Erros de campo e globais

Finalmente, vamos ver como lidar com erros de campo e globais usando jQuery:

var serverContext = [[function register(){
    $(".alert").html("").hide();
    var formData= $('form').serialize();
    $.post(serverContext + "/user/registration",formData ,function(data){
        if(data.message == "success"){
            window.location.href = serverContext +"/successRegister.html";
        }
    })
    .fail(function(data) {
        if(data.responseJSON.error.indexOf("MailError") > -1)
        {
            window.location.href = serverContext + "/emailError.html";
        }
        else if(data.responseJSON.error.indexOf("InternalError") > -1){
            window.location.href = serverContext +
              "/login.html?message=" + data.responseJSON.message;
        }
        else if(data.responseJSON.error == "UserAlreadyExist"){
            $("#emailError").show().html(data.responseJSON.message);
        }
        else{
            var errors = $.parseJSON(data.responseJSON.message);
            $.each( errors, function( index,item ){
                $("#"+item.field+"Error").show().html(item.defaultMessage);
            });
            errors = $.parseJSON(data.responseJSON.error);
            $.each( errors, function( index,item ){
                $("#globalError").show().append(item.defaultMessage+"
"); }); } }

Observe que:

  • Se houver erros de validação - então o objetomessage contém os erros de campo e o objetoerror contém erros globais

  • Exibimos cada erro de campo próximo ao seu campo

  • Exibimos todos os erros globais em um só lugar no final do formulário

7. Conclusão

O foco deste artigo rápido é levar a API a uma direção mais RESTful e mostrar uma maneira simples de lidar com essa API no front-end.

O front end do jQuery em si não é o foco - apenas um cliente potencial básico que pode ser implementado em qualquer número de estruturas JS, enquanto a API permanece exatamente a mesma.

Ofull implementation deste tutorial pode ser encontrado emthe github project - este é um projeto baseado em Eclipse, portanto, deve ser fácil de importar e executar como está.