Implementing Controller layer
Controller Layer contains the REST API endpoints which the service wants to expose. The code flow will start from this class. Controller class should be marked with @RestController
annotation.
Adding @RestController
is a convenient way of combining @Controller
and @Response body
annotations which eliminates the need to annotate each of the request handler methods of the Controller class with @ResponseBody
annotation.
Also @RequestMapping("/v1")
annotation should be added on top of the controller class. It will contain the version of the API(This will become part of the API endpoint url)
Each of the handler methods should be annotated with @RequestMapping
to expose them as REST API endpoints. Example - @RequestMapping(value="/document/_create", method = RequestMethod.POST)
Any request handler in the controller layer is going to have the following sequence of execution -
Making a call to the method in the Service layer and getting the response back from it.
Building responseInfo.
Building final response to be returned to the client.
For this guide, our controller class will contrain the following content -
@Controller
@RequestMapping("/voter-services")
public class V1ApiController{
private final ObjectMapper objectMapper;
private final HttpServletRequest request;
private VoterRegistrationService voterRegistrationService;
@Autowired
private ResponseInfoFactory responseInfoFactory;
@Autowired
public V1ApiController(ObjectMapper objectMapper, HttpServletRequest request, VoterRegistrationService voterRegistrationService) {
this.objectMapper = objectMapper;
this.request = request;
this.voterRegistrationService = voterRegistrationService;
}
@RequestMapping(value="/v1/registration/_create", method = RequestMethod.POST)
public ResponseEntity<VoterRegistrationResponse> v1RegistrationCreatePost(@ApiParam(value = "Details for the new Voter Registration Application(s) + RequestInfo meta data." ,required=true ) @Valid @RequestBody VoterRegistrationRequest voterRegistrationRequest) {
List<VoterRegistrationApplication> applications = voterRegistrationService.registerVtRequest(voterRegistrationRequest);
ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(voterRegistrationRequest.getRequestInfo(), true);
VoterRegistrationResponse response = VoterRegistrationResponse.builder().voterRegistrationApplications(applications).responseInfo(responseInfo).build();
return new ResponseEntity<>(response, HttpStatus.OK);
}
@RequestMapping(value="/v1/registration/_search", method = RequestMethod.POST)
public ResponseEntity<VoterRegistrationResponse> v1RegistrationSearchPost(@RequestBody RequestInfoWrapper requestInfoWrapper, @Valid @ModelAttribute VoterApplicationSearchCriteria voterApplicationSearchCriteria) {
List<VoterRegistrationApplication> applications = voterRegistrationService.searchVtApplications(requestInfoWrapper.getRequestInfo(), voterApplicationSearchCriteria);
ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(requestInfoWrapper.getRequestInfo(), true);
VoterRegistrationResponse response = VoterRegistrationResponse.builder().voterRegistrationApplications(applications).responseInfo(responseInfo).build();
return new ResponseEntity<>(response,HttpStatus.OK);
}
@RequestMapping(value="/v1/registration/_update", method = RequestMethod.POST)
public ResponseEntity<VoterRegistrationResponse> v1RegistrationUpdatePost(@ApiParam(value = "Details for the new (s) + RequestInfo meta data." ,required=true ) @Valid @RequestBody VoterRegistrationRequest voterRegistrationRequest) {
VoterRegistrationApplication application = voterRegistrationService.updateVtApplication(voterRegistrationRequest);
ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(voterRegistrationRequest.getRequestInfo(), true);
VoterRegistrationResponse response = VoterRegistrationResponse.builder().voterRegistrationApplications(Collections.singletonList(application)).responseInfo(responseInfo).build();
return new ResponseEntity<>(response, HttpStatus.OK);
}
}
*** NOTE: At this point, your IDE must be showing a lot of errors but do not worry we will add all dependent layers as we progress through this guide and the errors will go away.
Since the codegen jar creates the search API with search parameters annotated with @RequestParam
rather than taking request parameters as a POJO. For this, we will create a POJO by the name of VoterApplicationSearchCriteria
under models folder. Put the following content in the POJO -
@Data
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
public class VoterApplicationSearchCriteria {
@JsonProperty("tenantId")
private String tenantId;
@JsonProperty("status")
private String status;
@JsonProperty("ids")
private List<Long> ids;
@JsonProperty("applicationNumber")
private String applicationNumber;
}
Also, create a utils folder under digit. Add a new java class under utils folder by the name of ResponseInfoFactory
. Put the following content in this newly created class -
@Component
public class ResponseInfoFactory {
public ResponseInfo createResponseInfoFromRequestInfo(final RequestInfo requestInfo, final Boolean success) {
final String apiId = requestInfo != null ? requestInfo.getApiId() : "";
final String ver = requestInfo != null ? requestInfo.getVer() : "";
Long ts = null;
if(requestInfo!=null)
ts = requestInfo.getTs();
final String resMsgId = "uief87324";
final String msgId = requestInfo != null ? requestInfo.getMsgId() : "";
final String responseStatus = success ? "successful" : "failed";
return ResponseInfo.builder().apiId(apiId).ver(ver).ts(ts).resMsgId(resMsgId).msgId(msgId).resMsgId(resMsgId)
.status(responseStatus).build();
}
}
API recommendations:- Preferably, any services you develop should implement APIs for all 4 CRUD operations.