Skip to content

Instantly share code, notes, and snippets.

@thelowlypeon
Created November 6, 2014 17:31
Show Gist options
  • Save thelowlypeon/d9dc512501b54f0b4df8 to your computer and use it in GitHub Desktop.
Save thelowlypeon/d9dc512501b54f0b4df8 to your computer and use it in GitHub Desktop.
Proposal for EWG API/App Exceptions, validation, and error handling

Here's what I propose for our API validation, which comes almost entirely from Dingo.

For a store route (eg ListingsLocationsController::store()), we'd throw a StoreResourceFailedException:

# app/controllers/ListingsLocationsController.php
public function store($listingId) {
  $input = Input::all();
  $input['listing_id'] = $listingId;
  $location = new Location($input);
  if ($location->isValid() && $location->save()) {
    //do save stuff
  }
  else {
    throw new Dingo\Api\Exception\StoreResourceFailedException('Could not create new location.', $location->getErrors());
  }
}

Then, on the app side, in the EatWellGuide_LocationService, we'd catch a Guzzle ClientErrorResponseException so PHP doesn't freak out (additionally, we could catch a Guzzle ServerErrorReponseException, but I'm not sure we'll need to):

#craft/plugins/eatwellguide/services/EatWellGuide_LocationService.php
public function saveLocation($attr) {
  $client = new \Guzzle\Http\Client();

  $url = $this->getLocationUrl($attr['listing_id']);
  try {
    $request = $client->post($url, array(), $attr);
    $response = $client->send($request);
    return $response;
  }
  catch (\Guzzle\Http\Exception\ClientErrorResponseException $e) {
    return $e->getResponse();
  }
}

Then, in our controller, we need only check that the response was solid. If it wasn't, we pass along the errors as well as the message returned from the API:

#craft/plugins/eatwellguide/controllers/EatWellGuide_LocationsController.php
public function actionSaveLocation() {
  /* ... */
$request = craft()->eatWellGuide_location->saveLocation($attr);
if ($request && $request->isSuccessful()) {
  $this->redirectToPostedUrl();
  return true;
} else {
  //Log::info('Received a ' . $request->getStatusCode() . ' from Locations::save')
  $response = json_decode($request->getBody(true), true);
  $args = array('data'     => $attr,
                'errors'   => $response['errors']);
  craft()->userSession->setError(Craft::t($response['message']));
  craft()->urlManager->setRouteVariables($args);
  //continue to render existing template
}

And in the template, which is used for creating or editing:

#craft/plugins/eatwellguide/templates/locations/_form.html
{{ forms.textField({
  label: 'Location name' | t | title,
  required: true,
  name: "location[name]",
  value: location ? location["name"] : data["name"],
  errors: errors ? errors["name"] : null,
}) }}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment