Heavy, Engine, Ear
HeavyEngineer
Published on

How to query strapi v4 via graphql for unpublished content

It wasn't entirely obvious from the docs as to how to get these queries to work, so here are some crib notes.

Get published data

By default, Strapi will return your published data:

query {
  articles() {
    data {
      id
      attributes{
        publishedAt
      }
    }
  }
}

Get unpublished data

In Strapi, there is a an enum value you can pass to a graphql query publicationState which has two possible values 'LIVE' and 'PREVIEW'. So if you wanted to get all the unpublished articles in Strapi you would do this:

query {
  articles(publicationState: PREVIEW) {
    data {
      id
      attributes{
        publishedAt
      }
    }
  }
}

Get all published and unpublished data

Here is the graphql you want to query something in strapi and get both published and unpublished content you can batch up the queries like this

query checkArticleBySlug($slug: String!) {
  liveArticles: articles(
    filters: { Slug: { eq: $slug } }
    publicationState: LIVE
  ) {
    data {
      id
      attributes {
        publishedAt
      }
    }
  }

  previewArticles: articles(
    filters: { Slug: { eq: $slug } }
    publicationState: PREVIEW
  ) {
    data {
      id
      attributes {
        publishedAt
      }
    }
  }
}


Note that unpublished data has a null value for publishedAt.

Querying graphql from Nextjs 13 app directory

And here is the code i've used in a project to create a unique slug for submission to Strapi. The slug field can be automatically created when using the admin interface in strapi, but when using the API you need to ensure it's unique. The best way i've found to do this is to query the server and then use recursion to keep generating new random slugs and checking they are available before submitting them. Here's the code:

// create the slug. If it already exists, append a random string to the end and try again
// gradually increase the length of the random string until a unique slug is found
async function createSlug(
  title: string,
  length = 0
): Promise<string> {
  // slugify the title
  const baseSlug = slugify(title, { lower: true });

  // Generate a random string and append it to the base slug if not the first attempt
  const slug =
    length === 0 ? baseSlug : baseSlug + generateRandomString(length);

  // If the slug is unique, return it
  if (await isSlugUnique(slug)) {
    return slug;
  }

  // If the slug is not unique, increase the length for the next recursive call
  const increasedLength = length + 1;

  // Do 6 recursive calls and throw an error if still not unique
  if (increasedLength > 6) {
    throw new Error("Could not create a unique slug");
  }

  // Recursively call createSlug with increased length
  return createSlug(title, increasedLength);
}

async function isSlugUnique(slug: string) {
  // check if the slug exists in strapi
  const { data, error } = await getClient().query<GetArticleBySlugQuery>({
    query: GetArticleBySlugDocument,
    variables: { slug },
  });
  if (error) {
    throw new Error(error.message);
  }
  if (data.articles && data.articles.data.length === 0) {
    return true;
  }
  return false;
}

function generateRandomString(length: number): string {
  const characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let randomString = "";

  for (let i = 0; i < length; i++) {
    const randomIndex = Math.floor(Math.random() * characters.length);
    randomString += characters.charAt(randomIndex);
  }

  return randomString;
}

Read more about using gql and codegen here: https://www.heavyengineer.com/blog/graphql-apollo-typescript-nextjs-codegen-strapi