Full-Stack GraphQL with Absinthe, Phoenix, and React
GraphQL is revolutionizing the way developers build APIs.
Gone are the days when the server decided the shape of the response data. GraphQL puts the client in control so it can fetch exactly the data it needs and nothing more.
So what does it take to put together a full-stack GraphQL app using:
- Phoenix as the backend server,
- Absinthe for the GraphQL API, and
- React with Apollo on the frontend?
And how would you design it in a pragmatic, straightforward way?
Find out as we unpack a full-featured GraphQL app together, layer by layer!
“I love the Unpacked format with focus on design decisions and implementation details over pure code-writing. It's perfect for intermediate and above developers who want to understand the architecture and implementation... You provide the most useful technical training that I've seen on the web!” Wayne Hiner
“Loving this course! The example is amazing and real world. Pacing is solid. And as usual, the quality of your work speaks volumes.” Toran Billups
Break Down a Full-Stack App
Absinthe makes building a GraphQL API a breeze for Elixir developers.
Absinthe is a world-class GraphQL implementation in Elixir. Combine that with the super-fast Phoenix framework, and you've got yourself a robust, high-performance GraphQL API. Then build a frontend using Apollo React for a seriously cool full-stack application!
In this video series we explore the design and code of a full-featured application that let's you search for and book getaways to unique places.
Along the way you'll see the following concepts put into practice in a real-world application:
- GraphQL Schemas
- Queries and Mutations
- Subscriptions over Phoenix Channels
- Error and Loading States
- Ecto Schemas
- Apollo Client
- React-Apollo Components
- Client-Side Caching
We start with the completed app and unpack it layer by layer so you understand exactly how it works. No need to piece together solutions yourself. Use this full-stack application as a springboard for creating your own apps in a fraction of the time!
The Application We Unpack
How It's Designed
Wait, What Is GraphQL?
It's an expressive query language for your API that BLAH, BLAH, BLAH...
Indeed, our eyes glazed over every time we tried to write a definition for you. So we decided to take a different approach!
In our 4-part animated video series, you'll see GraphQL in action:
Videos just the way you like 'em: easy to digest, straight to the point, and paced for experienced developers.
Howdy! Before diving into the Absinthe + Phoenix + React app, let's make sure you have your development environment set up so you can explore the code and design alongside us.
The application we unpack lets us book getaways to some really cool and unique places. We can search for a place, book a place, and write a review for a place. To get a bird's eye perspective of the entire app end-to-end, we look at the overall design and architecture.
The first layer of app we explore is the data model. A good understanding of the four entities, their relationships, and corresponding Ecto schemas with changesets and validations is solid bedrock on which to layer the rest of the app.
Moving up a layer, we have Phoenix contexts that encapsulate all the low-level Ecto queries and database details. The first of which is the Vacation context which is the boundary layer for finding and booking places, writing reviews, and other vacation-related functionality.
All of the account-related functionality, including fetching, creating, and authenticating users is neatly wrapped in the Accounts context.
We start building the GraphQL schema using Absinthe macros: query, object, field, arg, and so on. First up is a query to find a specific getaway place.
To fetch the data that the place query asks for, we write our first resolver function which acts a conduit between the schema and the Phoenix contexts. We also begin to explore the GraphQL API using the super-useful GraphiQL interface.
Next up, we define a more complex GraphQL query which searches for places based on various criteria using a dynamically-built Ecto query.
It's idiomatic to organize resolver functions in separate modules, so we do a bit of refactoring. This kind of separation of concerns will serve us well as the schema gets more involved.
To query the bookings for a place, we write a custom resolver function and explore common pitfalls when querying relationships.
As the app stands now, we have a classic N+1 query problem. Dataloader to the rescue! It's an extremely powerful and must-have tool for crafting efficient GraphQL APIs. We start by giving Dataloader a whirl in IEx to understand how it works.
Now that we know how Dataloader works, we use it to efficiently load data in batches when querying for associations. The result is less code to maintain and no risk of N+1 query problems when requesting data.
Dataloader goes beyond simply loading data in batches. It also supports a flexible way to filter and order the data. We put that to good use by defining filtering and ordering rules for various query fields.
Next up, clients of the API need to be able to create, update, and delete data. To make that possible, we layer in mutations for creating and canceling a booking as well as writing a review.
Hold up! Only authenticated users should be able to create and cancel a booking, or write a review. So we need a way to authenticate users of the GraphQL API. To do that, first we add two new mutations: signup and signin.
Then we add a piece of Absinthe middleware that attempts to identify the user sending API requests. By making that user available to all resolvers, they can enforce authentication.
Now that the API can identify the current user, we add a new query to get the current user's info, including their bookings.
We cap off the GraphQL API with a subscription so clients receive live updates whenever a booking is created or canceled. Drawing on the power of Phoenix channels, Absinthe provides unparalleled support for GraphQL subscriptions.
It's time to turn our attention to the front-end application! To get our bearings and start on solid footing, we first explore how the React app is structured and organized with components and routing.
Now it's on to the good stuff! How do React components get data from the GraphQL API? Well, they don't interact with the API directly. Instead, the Apollo Client JS library acts as a very capable intermediary.
With an Apollo Client instance linked to the GraphQL API, we learn how to use Apollo React's Query component to fetch data from the API and render the results on the Home page.
Caching is difficult to do right. It's also essential if you want your GraphQL client to be snappy. Thankfully, Apollo Client has fantastic caching right out of the box. By default, it automatically and intelligently caches all query results. We go behind the scenes to get a glimpse of the cache in action so we can take advantage of it!
How do you implement a front-end component that runs a search query based on what the user selects as filter criteria? Search is really common and we show you how to do it.
The Sign Up form is indicative of many forms used to create entities by running a GraphQL mutation. We learn how to use Apollo React's Mutation component to run a mutation with variables bound to form data.
Various parts of our front-end app need to know if there's a current user, and if so, who they are. Our API already supports a query that returns the current user's info. So first we design a React higher-order component that fetches the current user. Then we learn how to cache the current user after they've signed up so the UI reacts immediately.
Designing a sign-in form that runs a mutation and updates the cache gives us an opportunity to apply what we've learned in a slightly different scenario. You'll come away with the confidence to implement any form-based mutations.
Signing out is straightforward, but we take it a step further by digging deeper into how Apollo Client's caching works so we avoid unnecessary API requests.
With authentication now in place, we're ready to explore how to query and mutate user-specific data such as a user's bookings. We use a query to fetch the current user's bookings and a mutation to cancel a specific booking. And we design another higher-order component that redirects to the Sign In page if you're not signed in.
The final page of the front-end app serves as an excellent capstone to the course. It puts together everything we've learned so far! We use a query to fetch all the details for a specific getaway place, including its bookings and reviews. We use mutations to create bookings and reviews, requiring a signed-in user. And we use a subscription to update the booking calendar in near-real time. We start unpacking this page by looking at the query and how it interacts with the cache.
Continuing on with the Place page, we use a mutation to create new reviews. This is very similar to other form-based mutations we've seen. But this time there's an interesting twist! When a new review is created, we learn how to update the cache so that the newly-created review is dynamically added to the top of the list of reviews.
The Place page also lets you pick a range of dates on a calendar and book a reservation, and that's yet another mutation!
In addition to queries and mutations, Apollo Client has excellent support for GraphQL subscriptions. Given a stream of subscription data, it's easy to merge that data directly into the Apollo cache. We set up the client to subscribe to booking changes and update the booking calendar in near real-time whenever a booking is created or canceled.
Most of the time you'll let Apollo Client cache all the query results and not think twice about it. But sometimes you need to refresh cached query results in response to a particular user action, such as creating a booking. We'll show you how!
Paginating query results is such a common need that Apollo Client makes it easy to do. We first modify our backend GraphQL API to support offset-based pagination. Then we tie pagination into the frontend so that getaway places can be fetched and displayed in batches.
What Does Unpacked Mean?
Deconstructing a pre-built app.
A step-by-step format for introductory courses is great for learning syntax, vocabulary, and basic concepts. But once you've got the fundamentals down, as an experienced developer your time is better spent:
- Deconstructing a full-stack application layer by layer to gain mastery, without the tedious typing of all the code
- Focusing on the design, architecture, and actual implementation of a sophisticated application
- Diving deep into the interesting parts of a complete, feature-rich application
What You'll Get
Lifetime access to everything you need!
Get started today!
No monthly subscription or time limit. You own it for life.
For Experienced Developers
You've got the fundamentals down and want to take the next step!
This course assumes you're already familiar with Elixir, Phoenix, and React and now you want to explore how all those things fit together in a full-stack GraphQL app.
Curious about GraphQL?
You've heard about it, and perhaps even noticed that some of your favorite platforms now support a GraphQL API. But you're wondering what all the hoopla is about. You need someone to cut through the hype and walk you through a pragmatic example of a GraphQL API and a frontend that uses it. In other words, you're looking to keep up to date with modern API development.
Considering GraphQL for your application and team?
You're already using the Elixir/OTP platform to good effect: it's robust, scalable, and fast! But perhaps your RESTful API isn't quite as flexible or maintainable as you'd like. Or maybe you're developing a new API from scratch and want to explore what GraphQL can do for you.
Creating a full-stack GraphQL app and need a jumpstart?
No need to get bogged down in figuring out how to put all the pieces together yourself. Save time and frustration by using our full-stack application as a springboard for creating your own app!
Created with 💛 by
Mike and Nicole Clark
You may be familiar with our step-by-step courses on Ruby, Rails, Elixir, and Elm. But what happens when you smash (pragmatically, of course) different languages, technologies, and frameworks together? Well, working at the system level gives you the power to create some very cool applications! We're excited to unpack these kinds of applications with you in the Studio. We hope you enjoy it!
With Help From
An Awesome Tech Reviewer
Many thanks to Bruce for reviewing the application code! His unique insights and suggestions based on hard-earned experience with GraphQL were instrumental in the design of this course.
Experienced devs love the Unpacked format!
Here's what some of them have to say…
“I love the Unpacked format with focus on design decisions and implementation details over pure code-writing. It's perfect for intermediate and above developers who want to understand the architecture and implementation without the tedium of watching instructors type out all the code. It's an excellent way to learn to do it yourself with great examples of how to go about it. You provide the most useful technical training that I've seen on the web!” Wayne Hiner
“I'm new to both Phoenix/Elixir and GraphQL but found this course to be very helpful. Everything was well-explained. Every single detail is referenced. No stone is left unturned and all the sections are well-paced.” Conroy Whitney
“I really liked that the GraphQL app was already made. That way I could follow along with and focus on the concepts, instead of worrying about making sure to type all the code correctly. I'd love to see more things taught in this format.” Chris Zimmerman
“I liked the in-depth usage of the Dataloader in this course. And the backend authentication / authorization middleware and ChangesetErrors module was nifty.” Hans Hoffman
“This is great!! The consistency of material—diagrams, code review, etc.—is solid. Even as someone without any Elixir or Absinthe experience whatsoever, the explanations and diagrams are spot on. Thank you for such a great code sample, including tests! I feel those are often overlooked/excluded in many educational products/tutorials, but what a great example you provided for further study. Well worth the price!” Rob Brennan
“@pragmaticstudio blows me away again, with their Unpacked: Full Stack GraphQL course. So information-rich, and still so clear and easy to follow!” Rebecca Le
“I had been researching Absinthe and Dataloader on my own from Hex documentation and YouTube tutorials, but I still had a bunch of serious gaps. This course really filled in my understanding! And the pacing was great, too.” Chris Roe
“Best GraphQL instructions I've ever seen! 5/5 stars! The visualization of the architecture was great. I love the data set I now get to play with!” Emilie Thoreson