How to fetch items by slug with Strapi, Nuxt and GraphQl

Website Development

Christopher Wray

This past week, I spent some time experimenting with the new CMS Strapi. I really like how easy it is to build api's for web apps and mobile apps in Strapi, and I wanted to give it a try. I was considering using it for a project, but I think I will hold off for now.

One thing we do very often in web apps and websites is we fetch different content from a database based upon the url that the user is visiting. That way, we design one template for all of our blog pages, and they are accessed at a url like "/blog/my-awesome-article".

When building a website with Strapi, you will have api endpoints to fetch items from the url right out of the box generated for you, but your api endpoints will be set up to fetch by the id of the article or item instead of a slug.

This is great for many cases as you may be accessing the data from a mobile app, and you won't need a user friendly slug anyways, or if you are wanting to update an item, you normally want to update items based on the id as this ensures you will only update the specific item you want to edit. (Id's are unique and auto generated.)

In my case, I was considering using Strapi as a backend for a web app, and I want users to be able to access pages from SEO friendly and user friendly slugs.

Therefore, I did some research and implemented this feature in my project. In this article, I will go into how to set up content types in Strapi to be accessible from a /slug uri versus the /id uri that is built in.

My tech choice was Nuxt for the front end, Strapi for the backend, and GraphQl for my query language.

Nuxt has built in functionality for Axios, and probably if I did an actual project with Strapi, I would just use Axios, as I am a fan of the Restful API convention, but I will leave that for another article.

Prerequisites for your app:

  1. You need to have a Strapi app configured and with the GraphGl plugin already installed. I won't go into this.
  2. You also need to have your Nuxt front end already set up and configured with the Apollo GraphQl module.

If you want to learn how to do both of these things, then I recommend this tutorial series.

It will also help if you know Vue, and how to create content types in Strapi. If not, you may have trouble with this.

Step One

First, add a text field in your content type for a "slug" in the Strapi Admin panel. After you have added the text field, you can also edit the field to be read only by configuring the view in the panel as well. You can add a placeholder that the slug will be automatically generated, so your editors don't think they need to edit it.

Step Two

Next, you will want to install the slugify node module. This is a sweet little package that does all of the hard work of creating a slug for you.

To do this, run the below in your terminal from your Strapi root directory.

npm install slugify

Step Three

Now that you have installed the slugify package, you will want to configure the model of your content type. Go to api/{ContentType}/models/{ContentType}.js and add a reference to slugify so that you can use it in your module.exports.

(Make sure to replace the {ContentType} with your model name. Strapi will have already built this for you.)

const slugify = require('slugify');

Then, add your options to the model. For my model, I wanted to save my slug from the name attribute, so this is what my .js file looked like when I was done:

Great! Now your model should automatically save a slug from the name attribute!

I also added the lower option to the slugify method so that my slugs would all be in lowercase. You don't have to do that if you don't want to.

Make sure to restart your strapi server.

Step Four

Now, I had to create a GraphQl query to access my content items by slug. In order to do this, I found out that I needed to create a GraphQl query that made a where clause on all of the content items, versus just doing a get request on the /model/slug. You have to search /model?slug=your-slug, with the api that Strapi provides out of the box, not /model/slug.

I was implementing this on a Company model/content type, so I added a query in /apollo/queries/company/companiesShow.gql.

(You will need to create the directory as this is just for organization.)

This is what my query looked like:

Of course, your query will look different based on what attributes you want to access.

What this does, is filter the resultes based on the slug, which I will add as a perimeter in the route. This returns an array of items filtered back which then you can use in your Vue page.

Step Five

If you haven't already, add a directory in your pages directory for your content type. As mine is companies, my directory was companies. This is important, as Nuxt will automatically generate routes for you based on your directory and page names. I had a page inside my companies directory of index.vue for my /companies page, and a _slug.vue for my /companies/slug page.

The _slug.vue file is where we will create the page for our content type.

Step Six

Now, you will want to import the graphql query and use it to fetch your company via apollo. This is what my _slug.vue file looked like after.

Great work! Now you should be able to access your content items at /companies/your-slug, or /model/slug if you edited the code to fit your set up!

Normally you will want to add an index page where you will see all of your items (or a paginated set of them.) In order to do that, add a GraphQl query for all of the items and add an index.vue file in the folder for your content type.

My index.vue file looks like this:

And my GraphQl query for getting all companies looks like this:

I hope this helps! I know there are a lot of moving pieces, and that is why I wanted to share. Have a better way to do this? Let me know in the comments!

May 29, 2020

Thanks so much for visiting our blog.

I'm Chris, the owner of our small company.

Please reach out if you are needing help in some way! We may be able to serve you.

Thanks so much for reading. I hope you enjoy the content here.

More For You