I use the Laravel framework.
I've got controllers, like CustomerActivityController
, and I've got a service layer with services like CustomerActivityService
.
Say I want to create a new customer activity via an API call in JSON format. The controller receives a JSON string as request data, and that JSON is parsed to an array.
array(
'user_id' => 9,
'customer_id' => 123,
'activity' => 'Made a phone call',
'date' => '...'
)
So my first step (in controller) is converting the input format to some universal data like an array.
Then I validate the values in the array, using Illuminate\Support\Facades\Validator
.
In my controller method, this looks like:
$dataArray = \json_decode($request->input('json'), true);
$validator = Validator::make($dataArray, [
'user_id' => 'required|integer|gt:0',
'customer_id' => 'required|integer|gt:0',
'activity' => 'required|string',
'date' => 'required|date'
]);
if($validator->fails()) {
// ... error response.
}
// Input considered valid, go on...
$this->_customerActivityService->createActivity($dataArray);
And I do it that way everywhere.
At the line $this->_customerActivityService->createActivity($dataArray);
The $dataArray
is still not really 'valid', because the user_id
or customer_id
could be incorrect (non existent for example).
I see this as a separate kind of validation, because this is not just validating raw data, but more in-dept logic based on other data. In my opinion, this should definitely be validated in the service. At least not in the controller.
The questions I'm asking myself:
I have validation in several different places. I could just move the raw-data validation to my service, but then the service is tightly coupled to the request format (because the service would get a
Request
object or JSON string as its method parameters). My service must be re-usable for any request type. (So I can have different controllers for Web/API/..., but the same service).I wonder how best to pass the data to the service.
Just accept an array as input to my service:
$this->_customerActivityService->createActivity($dataArray)
This seems to have the disadvantage that the array must have correct keys and doesn't miss any required segments. You have to know the array format and probably read the documentation of the service method, or read/analyze the service code.Have separate parameters for each 'property' of the data.
$this->_customerActivityService->createActivity($userId, $customerId, $activity, $date)
Advantage: method signature is descriptive. Disadvantage: the parameter list could be insanely long for bigger data structures, and you almost can't handle hierarchical data.Accept a data object.
$this->_customerActivityService->createActivity($activityInstance)
Since the raw-data validation is done in the controller, and the service does the 'logic' validation, the service 'trusts' its input. The service could accidentially be called with wrong input data if the programmer that uses the service made a mistake. Like putting -12 as a
$user_id
in a service method call.