Migrating to GraphQL on Laravel with Lighthouse

@all(model: "AppTicket") ticket(id: ID @eq): Ticket @find(model: "AppTicket")}Here we are just returning all of the available tickets in the tickets query.

Then in the ticket query we are returning the ticket that matches the id with @eq.

Here are the mutationscreateTicket( title: String @rules(apply: ["required", "max:255") contact: String @rules(apply: ["required", "max:255"]) status: String @rules(apply: ["required", "max:255"]) issue: String @rules(apply: ["required", "max:255"])): Ticket @create(model: "AppTicket")updateTicket( id: ID @rules(apply: ["required"]) title: String @rules(apply: ["max:255"]) contact: String @rules(apply: ["max:255"]) status: String @rules(apply: ["max:255"]) issue: String @rules(apply: ["max:255"])): Ticket @update(model: "AppTicket")deleteTicket( id: ID @rules(apply: ["required"])): Ticket @delete(model: "AppTicket")Here it is pretty straightforward.

The @rules directive uses the Laravel validation and will return an error if validation fails.

Here is the full schema file.

And that is it for the Laravel setup!.We can now delete the Controllers, Form Requests, Routes, and API Resources.

Vue Apollo SetupInstall the packages.

npm install –save-dev vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tagIn your app.

js file we need to configure Vue Apollo.

I like to create a separate Apollo configuration file and then import it into app.

js to keep things clean.

Here is a basic Apollo configuration.

This adds the required authentication headers to consume our GraphQL endpoint.

We can then import this configuration in our app.

js file.

We then need to add the Vue Apollo plugin and specify it in the root Vue instance.

Here is the relevant Apollo configuration.

The Client-side QueriesThere are different ways you can set this up.

You could hard-code each query into your components, but you will rewrite the same query many times if it is required in multiple components.

A better way is to put the queries into separate files and import them into your components.

This requires a graphql file loader and we can add this into the Webpack configuration.

I am using Laravel Mix in this demo.

Now create a queries folder in the js root to store all of the queries.

Create a new file called ticket.

gql.

Let’s break this down.

FragmentsI am using fragments to specify the ticket fields that we can query.

This isn’t required, but it allows us to specify a list of fields once and use it in multiple queries.

This also helps when adding new fields to a type, because we only have to update the fragment.

Queries and MutationsThe Queries and Mutations should line up with the Schema we created earlier.

Let’s look at the getTickets query.

We first start by specifying if we are creating a Mutation or Query (In this case it is a query).

Then we give the query an operation name (getTickets).

(Hint: This is the name we will use to import the query into our components).

Now we put in the name of the query we specified in the Schema, which is tickets.

Since our tickets query returns a user-defined type (Ticket), we need to specify which fields we want to return.

We can use the JS Spread operator to put all of the fields in from the fragment.

The rest of the Queries and Mutations have arguments that are required.

Arguments are specified in the first set of parenthesis with a Type.

Then they are then specified again after the Schema Query/Mutation name.

Think of it like you are instantiating the variables and then assigning those variables.

Check out the Official GraphQL documentation.

They go over all of this way better than I can.

Adding Apollo to the Ticket ComponentWe now have all of the leg work done and we can (finally) use the Apollo queries in our components.

We can specify Apollo queries by creating an instance property called apollo in components.

These queries will run automatically when the component is created.

Here is an example of the Tickets.

vue component moved to GraphQL.

ImportsNotice that I am importing the needed Queries/Mutations at the top of the script tag.

TemplateYour template section should go unchanged during this process.

We are using the same data just retrieving it in a different way.

QueriesThe variables property within the apollo queries should be an object that matches the arguments.

With the getTicket query we are only looking for something like {id: 1}, so we need to return this in the variables section.

I also mentioned earlier that there is a caching system built into Apollo.

These queries will also save to the cache and will pulled from the cache to reduce API calls.

MutationsWe specify a mutation by using the $apollo helper on the Vue instance.

this.

$apollo.

mutate({}).

The mutate function has config options that makes Optimistic Response and cache updates a breeze.

An Optimistic Response will provide a fake response with the expected data and will update or rollback if the mutation is successful or not.

You can see my use of this in the Update/Add Ticket mutations.

Don’t mind the __typename attributes.

GraphQL adds and removes these internally, so we just need to add them for the fake response.

Update Cache from MutationThe update property in the mutation will allow you to manually update the cache.

The update function expects the store and the Mutation’s response as arguments.

You can use object destructuring to drill right down to the data.

Looking at the addTicket mutation, I am loading the tickets array from the cache, appending the newly created ticket, and committing the changes back to the cache.

The cache and the data properties are reactive so the table will update automatically.

Protect those routes!As of right now everything works except our GraphQL endpoint isn’t being protected.

Anyone can browse to the Tickets page.

We can add the auth:api middleware to the GraphQL endpoint so that we are redirected to the login page if not authenticated.

Open up the lighthouse.

php configuration file and find the route property and add auth:api to the middleware array.

It should look like this.

'route' => [ 'prefix' => '', 'middleware' => ['auth:api'] ],Now we can modify the apollo.

js configuration to redirect to the login page on any 401 responses.

Do note that this is not spec compliant GraphQL, but it will work for a small app.

Here is the updated apollo.

js.

This adds a global error handler.

The 401 response will be a networkError and we are just looking for a 401 status code.

Then we redirect to the login page.

Notice we are importing the main Vue instance from the app.

js file.

That’s all FolksThat was alot to cover, but I hope that gives you a basic understanding of how GraphQL works and how you can integrate it into your app.

I plan to do an in-depth dive into the more advanced features like handling Laravel relationships, custom directives, custom resolvers, and much more.

Make sure you see the full code example on github.

If you have any questions, or concerns leave a comment!.

. More details

Leave a Reply