I've got a pretty simple web service that I need to add a PUT endpoint for that can handle upserts. This application is primarily a middleware layer to handle logging, caching and instrumentation in front of a third-party API that doesn't do anything useful like that, so it's fairly simple.
Once the endpoint receives a request, a bit of work is done in the service layer, it's transformed a bit and forwarded to the third party API, which sends back either a 200 if the resource already existed and it was updated, or 201 if it was created. I want to do similar with my endpoint, but I'm not sure how to propagate that difference from the client, through the service layer, and to the controller.
My initial thought is to just return the status code from the controller, and check for errors and throw exceptions in the service, and otherwise return the status code from the service as well so the controller can understand if an Update occurred, or a Create.
Essentially I'm looking at three layers like this, all using Spring Boot:
@RestController
@RequestMapping("/thing")
public class ThingController {
...
@PutMapping(path = "v1/thing/{thing-id}", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
public ResponseEntity<String> putThing(@PathVariable("thing-id") String thingId, @RequestBody ThingPutRequest thing) {
... validation etc...
HttpStatus response = thingService.upsertThing(thingId, thing);
// And then build the response with the status code based on what was returned, to indicate created or updated
}
}
@Service
public class ThirdPartyThingService implements ThingService {
private ThirdPartyThingClientClient thingClient;
...
@Override
public HttpStatus upsertThing(String thingId, thingRequest thingUpsertRequest) {
...blablabla...
return thingClient.upsertThing(thingId, transformedThingRequest);
}
}
@Component
public class ThirdPartyThingClient implements ThingClient {
...
@Override
public HttpStatus upsertThing(String thingId, ThingRequest thing) {
...
String requestUri = ...
try {
// It uses patch, and different errors return json or a string -_-;
ResponseEntity<String> response = thirdPartyClient.patch(requestUri, thing, String.class);
...
return response.getStatusCode();
}
catch (HttpClientErrorException.NotFound e) // and other exception handling where appropriate
...
}
}
This definitely doesn't look right to me. I don't like the idea of passing status codes around through the service layer, but I'm hung up on the idea of breaking up the service entry points because it feels like putting business logic in the Controller:
public ResponseEntity<String> putThing(@PathVariable("thing-id") String thingId, @RequestBody ThingPutRequest thing) {
if (thingService.resourceAlreadyExists(thingId) {
thingService.upsertThing(thingId, thing); // void return type
// build 200 response
}
else {
// call the same method
thingService.upsertThing(thingId, thing);
// build 201 response
}
}
I guess this really comes down to not really having a solid understanding of how to separate logic between layers, in Spring and in general. I'd love some thoughts specific to this, but would also appreciate any suggested reading or resources in the comments =)