a design and code exploration
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?
Find out as we unpack a full-featured 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 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
“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
Start With a Completed App and Break It Down
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 come away understanding how everything works together in harmony.
No need to piece together solutions yourself. Use this full-stack application as a springboard for creating your own GraphQL apps!
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:
37 Concise Videos • 4.5 Hours Total
Just the way you like 'em: easy to digest, straight to the point, paced just right.
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.
4. Vacation Context (9:53 and 2:48)
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.
5. Accounts Context (2:02)
All of the account-related functionality, including fetching, creating, and authenticating users is neatly wrapped in the Accounts context.
6. Absinthe Schema Definition (6:30)
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.
7. Resolving the Place Query (10:50)
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.
8. Querying All Places (8:06)
Next up, we define a more complex GraphQL query which searches for places based on various criteria using a dynamically-built Ecto query.
9. Resolver Modules (3:02)
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.
10. Querying Relationships (8:23)
To query the bookings for a place, we write a custom resolver function and explore common pitfalls when querying relationships.
11. Intro to Dataloader (8:00)
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.
12. Optimizing Queries with Dataloader (9:46)
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.
13. Dataloader Filtering and Ordering (9:28)
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.
14. Absinthe Mutations (12:14)
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.
15. API Authentication (9:58)
But not so fast! 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.
16. Authenticating API Requests (9:51)
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.
17. Current User Query (3:10)
Now that the API can identify the current user, we add a new query to get the current user's info, including their bookings.
18. Absinthe Subscriptions (9:26)
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.
19. React App Overview (7:59)
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.
20. Apollo Client (4:55)
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.
21. Query Component (10:57)
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.
22. Client-Side Query Caching (4:17)
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!
23. Searching For Places (9:50)
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.
24. Sign Up (10:13)
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.
25. Current User (8:38)
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.
26. Sign In (4:33)
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.
27. Sign Out (3:15)
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.
28. My Bookings Page (7:59)
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.
29. Place Page (6:49)
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.
30. Posting a Review (9:39)
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.
31. Booking a Reservation (7:07)
The Place page also lets you pick a range of dates on a calendar and book a reservation, and that's yet another mutation!
32. Subscribing to Booking Changes (10:42)
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.
33. Refetching Queries (3:13)
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!
34. Infinite Scroll Pagination (12:33)
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?
You're beyond a step-by-step intro course.
Step-by-step introductory courses are 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:
dissecting a full-stack application layer by layer without the tedious typing of all the code
focusing on the design, architecture, and actual implementation of a solid application
diving deep into the interesting parts of a complete, feature-rich application
In other words, we unpack apps in our Studio so you can put them together in yours!
For Experienced Developers
This course is for experienced Elixir, Phoenix, and React developers who are:
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 if GraphQL is a good fit 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 application and want 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!
New to Elixir and OTP? We've got you covered! Our 6.5-hour Elixir/OTP video course will help you master functional programming the Elixir way and take advantage of the power of OTP.
Still not sure if this course is for you? Ask us!
Bruce Williams is the co-creator/maintainer of the Absinthe project, the GraphQL toolkit for Elixir, and co-author of Craft GraphQL APIs in Elixir with Absinthe, published by The Pragmatic Bookshelf in 2018.
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.
Created by Mike and Nicole
Hi, we're real people just trying to share our passion for creating stuff!
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. Find out more about us…
What developers like you are saying about this course:
“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
“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
“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 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