Build an E-commerce Site with Next.js and Shopify
with Jason Lengstorf
Build a modern e-commerce web store using Next.js and Shopify. Jason will tackle building a custom app with a shopping cart in this episode.
Resources & Links
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
Big Hairy Dude, what a user name. (Laughter). Let's see. I'm going to put this project -- oh, wait. I need to do it here, don't I? What? What? Oh, because we started that project and killed it. So let me get rid of that one. I'll do another one. Here we go. Oh, Lee. What's up, Lee? So we're going to do the install here, get this all running. And now we have a basic Next app. So it looks like we got some pages. Gotten a API route. Got some public stuff, some global styles. So we'll go in and clean all those things up. We've got all the basic scripts. Only a few dependencies in here. So I'm just going to start this up with Netlify dev. All right. So there's our site. And that is all doing what I want. Good, good, good.
Oh, my goodness. Jonathan just showed up with the worst pun. The worst. Thank you for hanging out. It's good to see you. I haven't seen you in a minute. How you been, man? I know how to eat cheese. I know how to eat cheese. Can we do -- dang. Can we do that? Ryan, I'm not going to be building a checkout. I'm going to use Shopify checkout. I like that Shop Pay is just built in. So you get order tracking and those pieces without me having to do anything. And I just kind of am okay with the fact that the checkout looks like a Shopify checkout because honestly, I find that to build confidence. When I go to a store and hit their checkout page and it's a Shopify checkout page, I know that they're using Shopify. I know that the payment system is vetted. I know that it's not going to some rando's inbox and they're going to manually enter that credit card information. So I kind of prefer the Stripe checkout, the Shopify checkout. And from a developer standpoint, I want the easy thing, and it's definitely the easy thing. So, let's see. (Laughter). It's deadlines. Yeah, definitely got to get back to Portland. It's very hot here now, but dang, it's going to be cool. Yeah, yeah, yeah, the Shop app is kind of like built into the checkout. We can look at that in a minute here. So the first thing I should probably do is let's go to my Shopify store. Where is it? Shopify.com. I need to log in. I don't remember where. So I'm going to do it over here. That sounds right. I thought I was logged in. Are you looping me right now? No, here we go. So here's the Learn With Jason store. In it, I have a bunch of products. So we can see the products that are in here. We've got like sticker packs. We've got the Corgi duck. Then down here I have -- is it here? Where is all this stuff? Is that the wrong address in there? Boy. Where's my -- apps, that's what I'm looking for. Nope. Oh, no. They changed my dashboard. And now I don't know where things are. Store details, plan, online store, store importer, sales channels, develop for your store. Private apps have moved. That's what I need. Develop apps, Learn With Jason. And this, I think, is my -- I'm going to pull this off screen, just in case it shows a key. All right. So I have choose permissions, shared secret. I'm looking at this off screen because I can't remember if this API key needs to be private. I'm pretty sure the API key can be public, but the password is private. But just in case, I'm not going to show you either because I'm sneaky. So what I'm going to do is off screen here, I'm going to get a new window, pull this out. I guess I have to do it over here. And just take my API key in secret. Get those into a doc for myself so that I can use them. And that is how I'm going to actually hit the end point here. But then what I need is I need to go and find the -- let's go to the Shopify developer API. And I'm going to put this back up here. So I want to get a list of my products, and I think I can do that through store front API. That's the one I want. And I've got the GraphQL store front API, which is dope. I think I want the Node.js one. Npm package? Hmm. Hmmm, that's interesting. I've never seen that. So what's this going to give me? Let's take a look. So we're going to go to getting started. And I need to install Shopify API. All right. So let's start installing things here. I'll stop here and I'm going to npm install Shopify API. I'm not going to need .env, I think, because Netlify will already give me that. I'll add TypeScript as well, which I think is a dev dependency. We'll add it anyway. Doesn't really matter. Not using express. Examples. It was dev. That's okay. Oh, I'm going to need the node types as well. So then once I get down in here, do I really want to change a bunch of things? Is it going to -- maybe I'll just ignore that and see what happens. It's doing a lot here. Doing a lot here, y'all. What's up, Ricardo? Lots of first-time chats this time. What's up, y'all? Yeah, TypeScript should be a dev dep. That's what I thought. I should have listened to my gut. I didn't. I'll fix it. So let's go back over here. Going very slow. So here's TypeScript. I'm going to drop it down here. Then the other thing that I'm going to need is I also need node. That should fix -- did that break my stuff? Okay, good. Oh, damn it, I put it in the wrong place again. Again! Let me take this and move it down here. Do another one of those, make sure it's in the right place. Good. Okay. So now we have the Shopify API. We've got our node types. We have TypeScript. I don't actually -- you know what, I'm starting to think I'm severely overcomplicating this. I should probably just hit the end point, right? Let me -- do you just have, like -- what if I just want to call the thing? So you make a call. Get your active Shopify shops. Then I want to make a request. I don't know how I feel about this. This might be more than I need. Like, I kind of just want -- store front API call. That's what I want. So, got a shop, gotten a access token, and then -- I don't like this. Okay. No offense to the devs who built this. I shouldn't dunk on other people's code, but this feels like a lot. I don't want to use it.
Instead, I'm going to go to the Learn With Jason site, where I've made a call. I'm just going to copy the way that I did it there, which I think I did through just a straight-up call. So I've got a post to Shopify, which I'm going to need. So let's maybe dive into that function. I've got the utils folder up here. Here's my post to Shopify. And this is going to make a GraphQL call. So why don't we grab this, bring it out here. I'm going to set up -- how does Next handle utilities? Great question. Let's try. I'll set it up at the top. Let's set up a new file called utils. That's supposed to be a folder. Let's delete. And I'm going to set up a new one called utils. Then we'll just do Shopify.js, drop this in here, and let's just do a quick -- oh, I made this TypeScript. Is this going to explode? Good question. Don't know. I guess we'll find out. So I have the ability to post to Shopify. You send a GraphQL query and any variables you need. I'm going to -- this is not a TypeScript project. So I'm just going to drop the TypeScript out. Let's see. Then get rid of this. Do we have any TypeScript in here? No, okay. So we send a query and variables. We await a fetch. I'm going to have to install node fetch, which I can do here. Then we need to set up the Shopify API end point. So the way that works is I can go Netlify env set. Then I want Shopify API end point. And I need to figure out what that is. Because it's in the -- I guess I can just go look in my site. So if I go to app.netlify.com -- oh, I can show y'all something cool while we're in here. In the site settings, you can go to the build and deploy. Then check this out. This is cool. I'm going to go to labs. Then we've got deploy contexts for environment variables. So check this out. Now when I go into my sites, I go back in here. I'll go to my site settings. Then I'll have environment variables. So now I want to migrate my environment variables over here. And what that'll give me is all of my environment variables are now set up like in here, which is super cool. Then I can set them to only work in certain contexts. So if I edit this, I can say specific scopes. Now the environment variable only shows up in functions and not on builds. So this is super cool if you, like, need an API key to make an API route work, but you definitely don't want it to be available to the client-side code. You can just uncheck this. Like, how cool is that? So I'm not going to do that. I need this same thing, and there's nothing sensitive about this one, so I can just ta-da. I'm going to take that, come out here. I'm going to set it. This is going to fail because I didn't actually set up the site yet. No site ID found. So I'm going to Netlify link, and this is going to be to the -- I have to get out to the site I just set up over here. This one. And we'll go to site settings. It's going to give me a site ID. So I can copy that. And I'm going to enter a site ID. Bada-bing, bada-boom. So we'll run that Netlify env set again. And what this will give me, if I go and look at my environment variables now, is I've got my Shopify API end point. So this is pretty nice. It's set. It'll run now. I'm going to do the same thing -- let's see. If I hide this, oh, perfect. So what I can do is I can Shopify API key. Shopify store front API token is what it needs to be called. And that token is the one that I put over here. So I'll drop this in. And if I wanted to, I could set it up to where, like, we had a beta store. Oh, you son of a -- damn it. I'll go roll that token. Actually, the API key -- is the API key public? Does anybody know? The API key is not sensitive because you need the password to do any changes, right? What was I just looking for? Don't know what I was looking for. Just scanning the chat real quick. Yep, yep, yep. Lots of first timers here. Thanks, y'all, for hanging out. Benjamin, get to the CSS. I'm gonna. Let's see. Is there at least a learn how to build Shopify sites? There's a dev store that you can't go public with. So if you look at Shopify dev store, you can create a development store. This would be how you do one you want to learn with, but you can't actually sell anything through it. What else? Nettles, boops. What's up, Britney? Chris with the sub. Thank you so much. Hacked, yeah. Yep, yep. Yeah, so the Rust thing got reschedule. It's not gone. It's just going to happen later. We needed some more time for Syd to get his course launched. So stay tuned. We'll update the schedule once that's live. But today we're doing some Shopify. All right. So we've got this API token. I'm almost positive -- authentication. The API token header on all queries, right. So I'm not using the secret. So I'm just going to go ahead and trudge forward with this. I don't think we need to worry about this. This will let you read from the store, but that's okay because all the data in the store is read. I want that to be public. Yeah, Britney, the Netlify init thing would have done it, but I started it before, which created the site. Then I didn't finish linking it because I wanted to create the Next site first. So I haven't -- I didn't finish setting it up. So I'm going to have to do some manual things to make it all work. So I've got my token. Any other things here? Great. This is going to be my Shopify query. Then in the API routes, I want to create a -- we'll call it products.js. And I'm going to go back to my Learn With Jason code, where I've already done this. So let's go to products. If anybody wants to follow along, you can see the code to all of the Learn With Jason site here. This site is build in Remix, and it was super fun to build. There's a lot of cool stuff in there. Today we're playing with Next because Next is also fun, and I want to learn things. So let's build out -- this one is running TypeScript. So I'm going to export const -- or no, this is a Next API route.
So I have to go look at their API routes. I want to see example. Export function handler. One of these. So what I'm going to do is up here, I want to import from utils and Shopify. There you are. That's great. So then what I want to do is I want to get -- does this blow up? We're going to find out. So const data equals await, post to Shopify. Then we have our query, which I'm going to have to write, and variables, which I don't know if I need, but I'm going to get ready for that. And then we'll just return whatever we get back. So our query is going to match -- let's just use the same one I'm using on the site already. This will be my product list here. So this is all the data I use to get products on the Learn With Jason site right now. Let's just do a quick run through of what all that is because if you've never looked at GraphQL before, this can be a lot. The query name is get product list. The products themselves are going to be sorted by price. That's what the sort key is. And we're going to get the first 100 products. We order by reverse, presumably because that's what I -- I don't know why I chose to do that. Probably to put the duck at the top, would be my guess. Edges is a Graph theory kind of term. If you think about graph theory, you've got nodes. Those are dots. Then you've got edges, which are the lines that connect the dots. So edges can contain relationship data. Typically speaking, when you make GraphQL queries, at least in most basic use cases, edges is just the thing that wraps the nodes. So an edge is a relationship between nodes. The node itself is like one of the products. And then inside of that, I want the ID. I want its handle. Description, title, how many are left. Then variance is a Shopify thing where you get sizes or colors or things like that. So within the variance, I also want the edges and nodes. Then I want to get the title, how many of them there are, and the price. We also want to get the max variant price, the min variant price, in case you need a price range because you can do something where like an extra, extra small is $10, but a quadruple XL is a bigger item and costs more to make, so maybe that's $15. And you want to be able to show the range is $10 to $15. Then we want to grab any product images. In my case, I'm grabbing the first product image. But hey, any of y'all who have ducks, maybe send me images with the ducks. I know a lot of you have tweeted them. Maybe it would be found to put some people doing fun stuff with their rubber Corgi ducks. This is the duck, by the way. I love this duck. I get a lot of joy. (Audio feedback)
JASON: Is it still doing that? (Echoing). Okay. Okay. Nope, still broken. Check, check. We doing it now? Oh, my goodness. That was absolutely bizarre. Okay. Okay, I think I fixed it. I had to, like, quit my whole browser. That was the weirdest thing I think I've ever done on this stream. Because it was like my whole tech setup just, like, absolutely rebelled just now. So weird. Thanks for sticking through that with me, y'all. That was one of the -- that was a fun little mystery. Okay. Anyway, so now assuming I have done all of this correctly, which is a 10,000-foot if, let's start this thing up again. And because I have set those environment variables in Netlify, it will pull them down for me. That's part of the local dev experience, which brings me joy. And if I come over here and bring this back up and I go to API products, we get an error because I screwed something up, I think. Let's see. Unexpected end of JSON input. That's fair. But what was it? So we had all the pieces. The pieces should have been correct, but we're missing a thing. So the thing we're missing is -- oh, I have a theory. I think I got the wrong Shopify could or the store front API token. So give me a second off screen. While I update that token. Go to apps and go into my develop apps for your store. Going to get into this thing. Going to scroll on down past the admin API to the store front API, which is the one I actually needed. So let me copy that, and we'll go back into app.netlify.com. I am going to my site. Nope. I meant to go to the environment variables. Here. And then I need to update this one. So we'll go options, edit. And here's the new one. Save that variable. All right. So then we're going to stop and restart. Theoretically speaking, this will start working. Ta-da! Okay. So now we've got products, right. So let's see, we are just about halfway through the episode. We have some products. Those are being loaded on the page through an API route. I would like to use these now.
So let's go to my index.js. I'm going to -- let's just list them, which means I need to export -- is it a const? Let's go to Next.js, get static props. So export async function, get static props. Async function, get static props. That's going to return props, and inside of this, I want it to have my products. So I'm going to just hit that API route. So I'm going to do a const data equals an await fetch. That's going to require node fetch, I think. Let's see if it poly fills that for me. I'm going to get the API products. That should be all I need. So then we'll do then -- actually, I'm going to do it a different way. We'll do an if the response is not okay, we're going to console.error response. And we'll return. If we get down here, what I'll do is we'll get products equals res.json. We need to await that. So that'll give us our products. Then I can just drop the products right in here. So then to show that, we're going to get our products, and I can put together in here a pre, and we'll JSON stringify products and do some light formatting so it looks okay. And let's just give it a shot, see what happens. Only absolute URLs are supported. Okay. That's fine. We can solve that problem. What's the easiest way to solve that problem? I'm going to solve it by saying const URL equals new URL of either process.env.URL or we'll do HTTP local host 8888. Then we'll do URL.path name is going to be API products. And in here, we can do our URL to string. That should solve that problem, so let's try it again. So that didn't work. That means we should have a console error. And our console error is -- oh, it's picking up the wrong URL. Interesting. So it's pulling the URL there. That's fine. So I'm going to just -- we'll hard code is for now and remember we need to fix this later. Try again. Now we've got products. Okay. So now we've got our products. I want to clean this up a little bit, though, because we're not going to use all this data. Any amount of data we load in JSON is going to get shipped in the static props. Like whatever we return from static props is going to end up in the -- I think it ends up down here. Yeah, so this is all page bloat. You have to make sure you're only sending data you need, otherwise you end up shipping a whole bunch of stuff that's not relevant. So I'm going to do some data, like, modifying, massaging, whatever we want to call it. And let's see. Yeah, let's give it a shot.
So what I want -- let's design our ideal product here. So what I want is a title. Actually, I'm going to need an ID. I'm going to need a title. What else do we have on the store here? Let's go to the store and take a peek. We've got a title, a description, a price, and this add to cart button. That will put it over here. So let's get the title, the description. We've got the inventory. Look how many of these I have. Please buy a duck. Then I've got the price and this one. So I don't need to care about this price range because I don't think I have a price range on any of these. Let's just peek. Price range is the same on all of these. So there's no need to use that one. So I can skip that. With the images, I just need that first image. I didn't set alt text because I'm a monster. Dang it. Okay. So I need the description. I need the image. I need the price. They're all going to be USD. So I can make some assumptions for my store you would maybe not make for another store. Then we would have the -- actually, I don't need the quantity. I just need to know if it is in stock and probably I don't even want to return it if it's out of stock. Instead, we can just filter on quantity is over zero. Do we have any other quantities we want? I need the slug, which is the handle. And what else? I think that's it, right? I'm going to say yes because I don't have T-shirts or anything I would need. So what I can do then is I can loop through this. So products is going to be -- oh, wait. Products is going to actually be here. So this will be like data. And what I'm going to do with my products is do a data.products.edges. And we're going to map over that. Products.edges. Then each of these is going to be a node, which I'm -- we're just going to keep node. And inside here, I can return some pieces. So the first thing we want to do is say if the node.total inventory is less than or equal to zero, we're just going to turn false. Then we'll have to add filter Boolean, and that'll let us get rid of anything that returns false. Then what I want to do is return our object here. And we should be able to do that as ID would be .ID. The title is going to be node.title. Description will be the same. The image is going to be down here as node.images.edges 0.node.source. Ugh. So, we're just going to node.images.edges.0 -- oh, this is gross -- .node.source. Yeah, don't like that. And I'm actually going to change this to be a source and an image alt. And sorry, this is not ideal, but it's what I'm going to do because I don't have time to go write alts on everything. Then for the prices, what we want is the -- I guess we'll go, like, variance edges. Feels like this is the right price to get in terms of just general correctness. Price range would let me get there faster, but I'm not going to do that. So we're going to go with node.variance.edges zero. That goes into node.priceV2.amount. And that's going to be fine. Then slug is node.handle. Assuming I did all of that right and didn't typo anything, what we should get as a result is we should get back updated products that are much cleaner. There we go. And look how much less data this is, too. So this really simplifies the amount of data that gets sent to the browser, which is going to make the page perform a little better. That'll all be good.
The YouTube link on my Twitch bio is broken? Oh, that's not good. What did I do? Hm. Y'all don't like my cursive font? I like my cursive font. This is operator mono. It uses like an italic version for certain things. But you know, everybody is down on whatever you want to do. Ah, Dank Mono. Yeah, that's another one. I feel like everybody was using Operator Mono, and it cost money. I don't know how, but I talked myself into buying a font just for my software. I guess that's what it takes to be a hacker. So now I got my products. I want to make them actually show. And what I'm going to do with those products is, I think to start, let's just put a component right in here. I like this idea of making React, like organizing React code where everything is in one file until it gets uncomfortable to do so. So I'm actually just going to put the product component right here. What I want it to do is once we get one, we're going to return I guess it'll be a div. We'll give it a class name of styles product. Inside of it, we want to show image first. And do we want subpages? Yeah, we should probably try. Are we going to have time? We'll see. So I'm going to start with the image. It will be linked. That will be to /productslug. Let's subpage it. We'll go product. Then inside of that, we're going to do an image source, which will be product.image source. The alt will be product.image alt. What are you yelling about? Intrinsic elements. Oh, yeah, I probably should do that. We'll go with a product.title. Let's set up a paragraph that's got product.description. Let's then set up another one that's going to have a class name of styles.price. That will use product.price. Is that what I called it? And for that one, I probably want to do like a currency formatter, but because I am short on time, I'm going to just hard code a dollar symbol. Just because I don't want to get -- that's going to break on me, isn't it? Damn it. Okay. Just do things the right way. That's what you should do. So we're going to do formatted price. That's going to be new in intl currency. Number format. And options, we want currency is USD. Is that right? I'm just going to try this and see if it does what I want. So then formatted price is going to be formatted price.format. Did that do what I want? Let's try it. Oh, wait. I need to actually use this. So in here, we're going to products.map. We'll get the product. Then go with one of our products. How many times can I say product in one line of code? All of them is the answer. So if I did this right -- looks like I didn't. Missing key prop. It needs a key. Got it. The key is going to be the product.id. That's what we need it for. And now I have, look at that, there's our store. So let's do a little bit of styles. Not very many. And what I'm going to do is just set up a basic grid here. So let's go to our index. We have the products. Then we have a product. So inside of this, we're going to set up products as a displayed grid. I want grid template columns to be repeat three. We'll take a gap of like two rem. Then the product, I don't think, is going to need much. So actually what I'm going to do is just get one of these and let's see what that did. That's okay. Then let's also set the product H2 to be font size 1.25. A little less -- a little easier to read, right. So clearly my formatter didn't work because I didn't set it up right. So let's go get into the docs and see if we can find a currency example. We need style currency and then the currency style. That's what I missed. Let's go back into our index. We'll say style currency. Now if I did that right, there's our currency. Okay. So this is pretty cool. This didn't take much. It gave us what we wanted. We're happy. We've got a listing of products. Then what I want to happen is I want to show these products on an individual page. So for that to happen, we need to build another API route that is -- let's see. Data fetching. I don't need that. I need API route, and I want dynamic API routes, which will live at -- I guess I just need dynamic page routes. So I would set up, like, /product/handle or whatever. So let's go with product. Then it would be slug.js. Okay. So in this, I'm going to actually copy a lot of this out. Because I just want to kind of prove the concept. I'm going to call this one page. Then we've got our product itself. And I'm going to -- we're going to do a map, but this time instead of a filter, we can start with a find. So I'm going to find and we'll get the node. I want the node.handle equals, and we need the page slug, which I need to find. Where is it coming from? It's going to be like params or something. Can I see an example? Hmm. Dynamic routing. Show me one of these. And we get ID and comment out of the router.query. So I need to use router out of Next router. And that is going to live up -- that doesn't sound right. Doesn't sound right at all. What if we just do one of these to figure out what it is. I'm going to get args. Then I'm going to console.log args to see what's in there. And we get -- let's bounce to one of these. Unexpected token and no handle. Oh, that's right. So let's start by hard coding one of these. We'll say -- what is this one called? Rainbow Corgi toy. Okay. That should theoretically give us -- these were missing the styles. Oh, it needs to go up a layer. Get static paths is required. All right. So let's export async function get static paths. And that one is going to use the same data, actually. So I'm going to get this and put that up here. Then for this one, what I want is we're going to return -- where's a link to the get static paths? Return paths. So I need to return paths. And the path I want to return is going to be data -- where's my map? Then we're going to get our node. And in our node, we're going to return node.handle. That'll give us an array of paths so that we've identified all of the pages. URL is not identified. Oh, because we didn't grab that piece out. That's fine. We can go get that. So this is where I'd probably want it to be, like some kind of helper function. But that's okay. Callback must be returned. So we'll go false because I know that one exists, and I'm not going to look up the others. Path does not match the page. Provided path -- what does that mean? Oh, because I have to map these to include the whole thing. So product.edges.find.map. So I think then what I want to do is with this find, we will just find. Then I want to just update this piece. That's a Boolean. So this is inefficient, but it's a small list. So I'm not going to stress about it. I'm just going to put the find at the end. Then the filter is not going to work anymore because it's going to be single. Undefined reading handle. That's because we've changed it to a product. So instead, I'm going to get the slug. How about now? Product.map is not a function. Yes, it is. No, it's not, because we're returning product. That is a product. And this will then be product. Instead of an array, we're going to get a single, which means I'm going to drop this in like that. We don't need the key anymore. Ta-da! So now we've got the ability to do all of that, and I can put in something like a href. Let's go back because it's going to yell at me if I'm not using the Next thing again. Now we have boom. All right. So not perfect but also -- oh, because I hard coded. Hold, please. So we have to look and see what the our URL components are. So we get params and slugs. So I want get static paths params. Then here, I want it to be where we hard coded. It's going to be params.slug. Now we have a working store. We don't have checkout. I'm almost assuredly going to run out of time before we can do the checkout. So let's go back to the -- why not link? Honestly, I didn't --
I don't remember exactly the syntax. I would rather get the store than fix that error. So I'm going to go to Learn With Jason on GitHub. I'm going to see if we can do a really, really quick and dirty checkout page, just so we can see that flow working. I'm going to go in here, and there should be one called checkout. How does this work? Shopify, add to cart. Shopify, create checkout. So this is the piece I need, and we get a cart ID. Oh, no. It's got so many pieces that I don't have time to put in. Okay. So maybe let's talk through this so that it's not completely lost. But so the way this works is when you first load up a cart or when you load up the page, we need to create a cart. To create a cart, we go to Shopify. We try to get a cart using the ID. The ID is coming out of our -- where does it come in? It comes out of the event body. So we're posting it. And if we don't have one, then we create a new one. Right. So if we don't have a cart, then we return an empty cart. That's right. If we do have a cart, then we get all of the items in the cart and return those as our cart. And that's what this looks like. So you can see here I've got my cart. If I refresh the page, this is actually loaded from Shopify. So if I go in and look at my application and look at my -- I think it's in my local storage, I have cart ID. So this is my Shopify cart ID. This stays live with them and shows that I've added things to my cart. So that's what we're doing there. We're retrieving that cart. Then when I want to add something to the cart, I then take the product, which we get our cart ID and an item ID and how many of the things we want. So we post those, and that lets me run this add item to cart, which is -- where does that come in? Add item to cart comes out of this util here, which if I remember correctly, is going to be another GraphQL query. So once we've added it, we then update our cart. And we return the updated cart with the lines in it. If we don't have a cart, then we can create a new one, which is another function, create cart with item. That will then give us our new piece. Basically, this means if you don't have a cart, you can add something, and it'll create the cart on the fly. Otherwise, it creates the cart ahead of time, and you have one that's there, which is what happens when I refresh the page here. This is me looking at my cart. And that's loaded, so if I empty the cart, it'll say empty, refresh, gone, and I think if I reload this, yeah, the cart ID is gone. So it clears that cart ID. But if I add another one, I've got my sticker, and I've got a new cart ID. So this is my new cart ID that will persist. Whenever I reload the page, it shows me more things. So if I add another thing, it puts that in. Then as I add more stuff and navigate around the site, the cart stays persistent. That's the functionality there. Then if I want to go check out, I use my cart ID and say, hey, Shopify, give me a checkout URL. That checkout URL is going to be how we go to the Shopify checkout, which if I go here, that's this URL. So I'm going to click it. I'm creating a checkout. Then it's going to redirect me to that checkout. And you end up on the Shopify checkout page. So this is where you see the Shop Pay, Google Pay, Meta Pay, whatever you're using. If I enter my email, it'll automatically text me a confirmation code. So this is how all these pieces work. If I give you a discount code, you can use the discount code. So a lot going on here. In fact, here's what I'm going to do. I'm going to make a discount code for everybody right now. And let's call this one LWJ chat friends. This one is going to be -- we're just going to do a 20% off discount. So LWJ chat friends, and we're going to do a 20% off discount on any products, and we'll say -- yeah, yeah. And this is going to be good for the next, we'll say, three weeks. We'll end it on Friday the 26th. So if you get this code -- oops. If you use this between now and the 26th, you can get 20% off anything in the store. Let me save that and drop this one.
Here you go, friends. If you'd like to get anything from the store today, it's 20% off. All right. Let's do a little bit of looking at how the rest of that works. So on the client side, what we would need to do is on the page itself, which is here, then we've got -- yeah, there we go. I've got my routes, and I've got the store. I think I did all the coding here. So you get all your products, and we format cart. Where's my checkout button? Checkout button sends to API store create checkout with the cart ID. This is what's cool about this. There's no magic here. You're just posting to this API route, and then that API route that we looked at up here -- Netlify functions, create checkout -- it's going to get that checkout URL. And do you see here how I'm doing a redirect? So basically, we create this and then immediately redirect to the new URL. That's how you get that experience of clicking the button. Then you get to the checkout page and everything works. So what I need to do and what will happen in the future is we'll go through and actually clean this up so that each one has its own page. These need to have their own presentation layer so they can be a little nicer looking when they're on a single page. I'd love to be able to show, you know, like I said, if you get one of these rainbow Corgi toys, send me a picture of it. I've seen a lot of really cool ones. People put them next to their actual Corgis. People had some fun stuff where they set them up on their desks. If you have any of those, send them to me. Maybe this next iteration that has product pages will be -- will include those. I mean, obviously if you give me permission to do it. So lots to do still to make this actually functional, but it's fun. I'm happy about it. I think it was cool that we were able to get this far on an e-commerce store in just, you know, about an hour and 15. And that five minutes of me just having to shut down the whole stream while things echoed. So not bad. Not bad at all, everybody. I'm pretty excited. Yeah, Josh is calling out that Kelly did an episode with me where we set up a checkout. So let me find this episode here. Custom cart. There we go. So this is a whole episode that you can watch where we set up the cart. This is the process of getting the cart set up and created, of adding things to it, removing things from it, and creating the checkout URL. So this was part of Jamstack Conf 2021. So last year. And we used the store front API. This was a super fun episode, part of a much bigger app where we built out a whole Shopify store front. But yeah, lots and lots of good things going on in here. Definitely worth checking this one out. Kelly is very funny and very knowledgeable. So make sure you go give that a look.
Any questions, chat? We got a little bit of time. Not enough time for me to really build anything, but enough time for me to maybe deploy this. Why don't we do that, actually. If y'all have questions, ask them. While you're doing that, I'm going to deploy this thing. So I'm going to do a readme. It's one of these. There it is. Insert snippet. Then I do this LWJ snippet thing. Then I grab the episode name. Then I got the episode slug. Drop that thing in here. Demo name is going to be LWJ store Next.js Shopify. That's going to be the repo name as well. It asked me for a description, so I copy/paste the one from the description. So then I'm going to git add all. I'm going to git commit and say code after episode. And we're going to git hub repo create. I want to push the existing repo to GitHub. That's this one. LWJ store Next.js Shopify. Good. But I want it to be on the Learn With Jason repo. So I'm going to copy this and drop this in. I'll put it in the org. It's going to be public. And I do want to add a remote. Origin is good. Would I like to push? I would like to push. So then I guess I need to upgrade my GitHub CLI. Yeah, then what happens? Then because I started setting this up sort of oddly, I'm going to finish in the browser. The environment variables were already set up. I don't have to do anything. I am going to go over here to the link repository. I'm going to use GitHub. I don't need the Netlify account. I'm just using my own. So I'm going to get Learn With Jason. We're going to search Shopify. I have a million repos, so that takes a minute. There's my new setup. And it's smart enough to know -- do I have a yarn? I do have a yarn lock. Mmm, I don't want to use yarn. So I'm going to get rid of the yarn lock. I'm going to go back into my package JSON, make sure it's not using yarn. Okay. And then I'm going to do npm run build. And -- oops. Don't need to hit save. It's a website. We've already got those. So I'm going to deploy. And it's off to the races. It should just work. Let's -- I feel like when I get out of the automatic setup like I just did, sometimes I forget a step. So this first one might give me an error. Then I'll have to fix a little piece. Why not yarn, out of interest? To be completely honest, my preference, it really is just I don't have -- I use npm. So that's my thing. Let's see. Use npm. I think this is actually going to fail because I didn't have the -- I think I missed all the pieces because npm isn't there. Why doesn't it like that? Are you going to freaking fail because I'm -- oh, that is uncool. Like, I get that linter errors are there to help you, but that's -- that is not great. So what do I need to do? I need to go and get these images. Will it import for me? Of course not. Let's see. Import image from next image. Then what is your API? Image source. Alt probably. I hope that works. I'm just going to leave it alone. Then do I need to do anything -- does that automatically come in? It does. And what is the API for these? Did they finally fix this? Make internal props. Then we can go back up to our index and do the same thing. So give me an image. That needs to come in from next image. Then we need a link. That's going to come in from. I hope this works. Just start it up again and see. Must use width and height or layout fill. Fine. Like that. This is where a linting error would be helpful. But it doesn't have one. Here's my product. Invalid source prop? Yo, you're killing me. Don't make me use -- don't fail my builds on your silly stuff if you're not going to just work. Now I need to do this. And now you'll work? I did configure it. Images. Module exports, yeah. Do I have to stop and restart? Restart the server, okay. Cool. Yep, that's what you would expect it to do. That makes sense. Okay. So I guess we'll switch out the image. I'm almost out of time. So, cool. Yeah, this is fine. We're going to do width equals -- how big was it supposed to be? Maybe 200. Does that work? Width and height.
So hopefully these are all square. No, that should be right. If I make it 400, does it blow things out? So I'm going to have to do the same thing on the other one. And now it all works. I don't see any errors. So let's try this one more time. Git commit. Push. And now it's going to build and actually run this time. So off we go. Don't you fail me on a linting error. All right. Did y'all come up with any questions? No questions I'm seeing. So while we're waiting for that to build, which should only take a minute, let's do another quick round of shout outs. So I'm going to give a shout out to Rachel with White Coat Captioning. Home page. We've got all the captions coming to you live. That's White Coat Captioning on the scene. That's made possible through the support of our sponsors. Netlify, Nx, and New Relic all kicking in to make this show more accessible to more people. And we've got a lot of good stuff coming up. I just sent over some new episodes to get added, so this list is incomplete. But later this week, we are going to be working with Varun on automated accessibility tests with Storybook. I'm pretty excited about this. Storybook is in a lot of teams' workflows. And accessibility is one of those things you want to do, and it is sometimes confusing and really, really easy to miss stuff. So automating some accessibility tests is going to level up your team and get you a lot of good stuff. We've also got fun stuff coming up. I think next week we're going to have Fred back on the show to talk about Astro1.0, which is dropping also next week on Monday. So that's exciting. Get ready for Astro 1.0. We're going to talk about what that means. All sorts of good stuff coming. Oh, Adam our Guile is going to come on. We're going to talk about CSS open props, which is sort of like -- it's like CSS variables that you can import and use sort of like you would do Tailwind or something, but you don't have to install anything. It just works. I'm very excited about it. I've been following Adam's work for a long time. This is going to be an exciting one. Then we got Will coming on. We got David coming back on. We're going to talk about some state machines, I think. Just a lot of good stuff coming up. Make sure you add on Google Calendar. That'll put the episodes on your calendar. You can follow on Twitch. You can also find me on YouTube, since it appears I broke the YouTube drink, I'll drop a new one. This is the correct link. So you can go follow Learn With Jason. And my build freaking failed again. Why? Oh, gosh darn it! That's annoying. So my API route is going to fail because I have to deploy the API route to call the API route, which means that I can't call it. You know, I'm going to have to fix this off stream. Basically what that means is in order to do what I am doing, I need to deploy the function and then do it. So in another project, what I'd probably do is deploy an API separately so I could use the API to build the site.
I could also build all that API stuff into Next, but if I want to use it somewhere else, I'd like to be able to use it. I guess I could put -- well, I did put it in an API route, right? But -- yeah, I don't want to build it into the server page because I want to be able to get to my product. So I just need to do a little bit of clever deployment. I'll turn off the product loading, deploy the site so it doesn't call that API route. Once it it's deployed, I'll turn it back on. That'll fix the whole thing. But yeah, stay tuned. You can follow along with the git history. That's go live here as soon as I get time to fix it. Otherwise, thanks, y'all. Appreciate you hanging out. As always, it's been a blast. So let's go find somebody to raid. We're going to go see Ben Myers, who's I think about to go live. Is that right? Yes. So we're going to go raid Ben. Everybody go say hello. We'll see you all next time.