spa-starter-kit: Error Handling, Validators, the Interceptor and Response Formats

Just a few thoughts, suggestions and observations here…

There are a few strategies in Laravel/Eloquent for creating and saving models. We typically test for…

// We have static event rules on the model. This will return a 422 invalid entity response
$this->validate($request, Product::getCreateValidationRules($id), Product::getCreateValidationMessages());
$attributes = $request->all();
$event = new Product($attributes);
if($event->save())  {
    ...
   // Send success response - 200
} else {
  // Send failed response - or exception 
}

Or for updates…

$this->validate($request, Product::getUpdateValidationRules($id), Product::getUpdateValidationMessages());
// This will automatically send a 404 not found response - although probably not what you 
// want if you are going to transform the output - see below...
$event = Product::findOrFail($id);
$attributes = $request->all();
if($event->update($attributes)) {
   // Send success response - 200
} else {
  // Send failed response - or exception
}

Sending a response of return $this->response([ 'result' => 'success',]); is okay, but slightly RPC-ish in so far as the result status is duplicated by the http status - 200 is okay, 422 validation failure, 400 invalid client data, 500 server error etc.

Also I see you’ve included league/fractal package for response transforms which is excellent. The maintainers of the package refer to HAL, and JSON-API as possible output formats. A complete API design might be outside the scope of your starter pack - but there are some great pointers in http://stateless.co/hal_specification.html, http://jsonapi.org/format/ (albeit a bit 'rails-ish) , and even https://github.com/argo-rest/spec Here’s an example format for an in-house API we created. Error, and Errors are first class - https://gist.github.com/58bits/aa14c7a8f525a074f7a6aaf5b9dd60b6

It might be nice if you created a simplified version of any of the above, using league/fractal transformer to create an API response format to abstract away from Laravel’s default Json response - which would nicely decouple your starter-pack from Laravel itself.

Also in terms of handling errors in the http plugin (Axios) - you’ve got a great global error handler in the interceptor, but sniffing for the return type (array or object) to determine the error type is a little brittle. With a standard response format, and errors, response codes, all first class, you can make the switch based on the response code and data itself (e.g… 422 for invalid entities etc. - and then check for the error or errors properties.)

In the http client for the entities/forms, I also think you still need a catch handler (even if it’s empty), for example…

update () {
        this.$http.put(`events/${this.event.id}`, this.event).then(() => {
          /**
          * This event will notify the world about
          * the event creation. In this case
          * the Event main component will intercept
          * the event and refresh the list.
          */
          this.$bus.$emit('event.updated')

          /**
          * Hides the global spinner
          */
          this.setFetching({ fetching: false })

          /**
          * Sets the global feedback message
          */
          this.setMessage({ type: 'success', message: 'Event was updated' })
        }).catch((error) => {
          console.log('our own error handler.')
          console.log(error)
        })
      },

… Otherwise axios will generate an uncaught in Promise exception, and dump this to the console as…

Uncaught (in promise) Error: Request failed with status code 422
    at createError (eval at <anonymous> (app.js:876), <anonymous>:15:15)
    at settle (eval at <anonymous> (app.js:1104), <anonymous>:18:12)
    at XMLHttpRequest.handleLoad (eval at <anonymous> (app.js:858), <anonymous>:77:7)

Very lastly, just in case you or anyone else is using Xdebug to debug your PHP API server (Laravel in this case), here’s an updated interceptors.js file, which will add the XDEBUG_SESSION_START parameter to the query string (or post values) for all requests, to tell XDEBUG to debug the request. This is a a little hacky, and I’m using PHPStorm as my debugger client. The session identifier is generated by PHPStorm (which is listening for incoming Xdebugger requests). XDEBUG_SESSION_START can be used for the same session repeatedly, and it’s a better method than trying to set the XDEBUG_SESSION session cookie, as cookies will fail to be set if you’re making a CORS request to the API server.

https://gist.github.com/58bits/c7b7dccf3f922fde13275d1a54990838

And the PHPStorm docs for setting up Xdebug here… https://www.jetbrains.com/help/phpstorm/2016.2/configuring-xdebug.html

Hope some of this helps, and thanks for the great starter kit. It’s helping us a lot in getting started with Vuejs.org.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 3
  • Comments: 17 (11 by maintainers)

Most upvoted comments

My pleasure - and take the hypermedia-based API response formats with a pinch of salt. You probably don’t need to go down the ‘HATEOAS (Hypermedia as the Engine of Application State)’ rabbit hole (https://sookocheff.com/post/api/on-choosing-a-hypermedia-format/). I’m sure a simpler ‘standard’ JSON response format for your starter kit would be fine.

@58bits Yes, I also think that a transformer for errors messages would be nice, please send us a PR 😄

I just took a quick look at the ProductTransformer output (here’s a pretty formatted Gist… https://gist.github.com/58bits/f71ba4cc77a255bb53446463d115d87d). This is great.

Assuming you don’t go for a full-blown hypermedia-based API (which would include link relationships, actions etc.), and are keeping route definitions in the Vuejs.org router, then the only thing that might be nice, is if you also create a transformer for errors ( in particular where you’re relying on $this->convertValidationExceptionToResponse($e, $request); for validation errors).

The error responses would have a top level property of ‘error’ or ‘errors’ (instead of ‘data’), with message(s) beneath those. Your http interceptor, store.setMessage, and alerts.vue component could then be modified accordingly.

I think it’s also good practice to include the official httpStatus code, and httpStatus message in the response object (also top level) for cases where the response object may have been relayed from another service, or is past along in the client.

If I have time over the next couple of weeks, and assuming no one here has taken a stab at it, I’ll submit a PR.

Have a great holiday season if all is quiet before then!!!

@58bits no worries, it’s always good to have tips and suggestions like yours, and PRs are very welcome, if you wanna put some of thos ideas in the code, thanks 😄

@flyingluscas ah yes of course - I’d forgotten about app/Exceptions/Handler.php - that makes sense. In our case will need to check if($request->ajax()) before formatting the result since we have both a regular server-side app and API server on the same Laravel instance.

Thanks @58bits , those are some very good tips 😄

About the error handling, right now we have been using the app/Exceptions/Handler.php file to format the output of most of the exceptions. I think it’s good idea to use the Laravel’s exceptions handler because it free us of always worrying about exceptions on our controllers.

And about the response format of the API, I was thinking of changing to JSON-API, because the project isn’t that complex, and as source of knowledge, it would be simpler to use and understand. But I’am new on the API field, so I’m just using the DataArraySerializer of fractal, that is quite simple too, I dont think there is any need of applying something more complex right now.

Hello 58bits, thanks for the suggestions.

In relation to debug with phpstorm, I prefer to use debug environment based on environment variables, where I start the api project with the php built server.

Follows a reference.

Http://tech.mybuilder.com/phpstorm-configuring-and-using-xdebug/ Or vagrant-based debug environment: Https://www.sitepoint.com/install-xdebug-phpstorm-vagrant/

In these ways, it is not necessary to send the data via parameters in the url.

@58bits thanks for taking the time to review the code and write out all those suggestions!

I’ll dive in ASAP to check them out! Also I’m mentioning my fellow developers @flyingluscas @cristianopacheco and @vinicius73 so they are also be aware of this ticket.

Let them comment!

Best regards,

Vedovelli