Use slugified titles for URL in Next.js with the Notion API

Jon Meyers
InstructorJon Meyers
Share this video with your friends

Social Share Links

Send Tweet

In this video we refactor the structure of our recipe details URL to use its slugified title, rather than its ID. In order to accomplish this, we use an npm library called slugify. This is a function that allows us to pass in a string in sentence form, and get back a hyphenated version that we can safely use in our URL.

Since our recipe details page is using the recipe's ID to request data from Notion's API, this requires us to make some additional requests and manually work out which recipe correlates to the URL's slug.

This gives us a much prettier URL to send to people and, since the URL now contains the title of our recipe, it communicates much more clearly what to expect when the link is clicked.

Jon Meyers: [0:00] Using our recipe's ID in the URL is a little bit ugly. It also gives us no context on what we're about to click on. Let's replace this with a slugified version of our recipe's title.

[0:12] Back over in our Next JS application, we are going to install a new library called Slugify. Once that's finished, we can restart our server and import our new slugify function. Now we can replace the part of our URL that specifies the ID with a call to that function and pass in our recipe.title.

[0:32] Since this is a unique value, we can use this as the key as well, which means all we need is our recipe.title. Let's go back to only returning that from getStaticProps.

[0:42] Now recipe in our component will just be a string so we can get rid of .title. If we save that and refresh, everything should look the same, but if we click one of our recipes, we can see that we're now navigating to a slugified version of that URL, and we're getting a 404 page.

[1:01] I prefer my URLs to be lowercase. I'm going to chain on a call to .toLowerCase. If we go back to our recipes list and click Pasta Pesto, you'll see that that's fixed up our casing, and so now we just need to implement our recipe details page.

[1:16] The first thing we'll need to do is rename our page to be slug instead of ID. Then in our getStaticPaths function, we need to specify our parameter as being slug instead of ID. That's going to be set to a call to that slugify function, but this time we're going to pass in result.childpage.title. We'll need to import our function up here.

[1:42] If we have a look at how those paths are structured by console logging them out, we'll see that they have that same problem of capitalization. Here we can say, .toLowerCase. That's looking much better. We can get rid of that console.log now.

[1:59] In getStaticProps, we are going to receive our Slugify title instead of an ID. We'll need to work out which recipe is associated with that slug so we can pull out the ID that's used by the page query and also the blocks query.

[2:14] We can use the same query that we have in our recipe list, which gives us all of the blocks in that top level page. We then want to iterate over each of those results and find a result that matches our slug. Again, we want to check if our result.type is equal to childPage.

[2:34] If it is, then we can destructure our title from result.childPage. Then we can work out our results slug by slugifying that title and again, converting it to lowercase. We can return whether our result slug is equal to our slug that we were passed in via our params. In case our result type is not a childPage, we just want to return false.

[3:07] This is going to return us our page data and so we can create a variable called page. We can get rid of this one because we now have our page data. Here in blocks, we're just going to replace this with page.ID, instead of ID. Then our title can be pulled out of page. childPage.title.

[3:27] If we refresh our page, you'll see that we have our recipe details back. If we go back and click this Thai Chicken Risotto recipe, we can see its details and this beautiful slugified URL.