Strapi part 2: GraphQL and Content Management

Published: Nov 2, 2023 by Isaac Johnson

Earlier this week we looked into setting up an on-prem Strapi instance. The whole reason for a Content Management System (CMS) is to, well, store some content.

Today we’ll create a simple Album Catalog and populate it with data (I’ll use some of my latest LPs purchased). We can then setup the GraphQL plugin and show how to use it.

/content/images/2023/10/20231027_075133.jpg

GraphQL setup

Let’s look up the install command from the marketplace

/content/images/2023/10/strapi-16.png

The install command:

$ npm install @strapi/plugin-graphql --save

npm WARN deprecated apollo-server-plugin-base@3.7.2: The `apollo-server-plugin-base` package is part of Apollo Server v2 and v3, which are now deprecated (end-of-life October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.
npm WARN deprecated apollo-server-types@3.8.0: The `apollo-server-types` package is part of Apollo Server v2 and v3, which are now deprecated (end-of-life October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.
npm WARN deprecated apollo-server-env@4.2.1: The `apollo-server-env` package is part of Apollo Server v2 and v3, which are now deprecated (end-of-life October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/utils.fetcher` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.
npm WARN deprecated apollo-server-errors@3.3.1: The `apollo-server-errors` package is part of Apollo Server v2 and v3, which are now deprecated (end-of-life October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.
npm WARN deprecated apollo-datasource@3.3.2: The `apollo-datasource` package is part of Apollo Server v2 and v3, which are now deprecated (end-of-life October 22nd 2023 and October 22nd 2024, respectively). See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.
npm WARN deprecated apollo-reporting-protobuf@3.4.0: The `apollo-reporting-protobuf` package is part of Apollo Server v2 and v3, which are now deprecated (end-of-life October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/usage-reporting-protobuf` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.
npm WARN deprecated apollo-server-koa@3.10.0: The `apollo-server-koa` package is part of Apollo Server v2 and v3, which are now deprecated (end-of-life October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.
npm WARN deprecated apollo-server-core@3.12.1: The `apollo-server-core` package is part of Apollo Server v2 and v3, which are now deprecated (end-of-life October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.

added 94 packages, and audited 1541 packages in 11s

170 packages are looking for funding
  run `npm fund` for details

4 high severity vulnerabilities

Some issues need review, and may require choosing
a different dependency.

Run `npm audit` for details.

We also need to create a plugins.js file

builder@LuiGi17:~/strapi_k8s2/strapi-project$ vi config/plugins.js
builder@LuiGi17:~/strapi_k8s2/strapi-project$ cat config/plugins.js
module.exports = {
  //
  graphql: {
    config: {
      endpoint: '/graphql',
      shadowCRUD: true,
      playgroundAlways: false,
      depthLimit: 7,
      amountLimit: 100,
      apolloServer: {
        tracing: false,
      },
    },
  },
};

We can (re)build with Docker

builder@LuiGi17:~/strapi_k8s2/strapi-project$ docker build -t harbor.freshbrewed.science/freshbrewedprivate/strapidev:v5 .
[+] Building 22.8s (15/15) FINISHED
 => [internal] load build definition from Dockerfile                                                    0.0s
 => => transferring dockerfile: 466B                                                                    0.0s
 => [internal] load .dockerignore                                                                       0.1s
 => => transferring context: 54B                                                                        0.0s
 => [internal] load metadata for docker.io/library/node:18-alpine                                       1.1s
 => [auth] library/node:pull token for registry-1.docker.io                                             0.0s
 => [internal] load build context                                                                       0.0s
 => => transferring context: 3.00kB                                                                     0.0s
 => [1/9] FROM docker.io/library/node:18-alpine@sha256:435dcad253bb5b7f347ebc69c8cc52de7c912eb7241098b  0.0s
 => CACHED [2/9] RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng  0.0s
 => CACHED [3/9] WORKDIR /opt/                                                                          0.0s
 => CACHED [4/9] COPY package.json package-lock.json ./                                                 0.0s
 => CACHED [5/9] RUN npm install                                                                        0.0s
 => CACHED [6/9] WORKDIR /opt/app                                                                       0.0s
 => [7/9] COPY . .                                                                                      0.1s
 => [8/9] RUN chown -R node:node /opt/app                                                               0.9s
 => [9/9] RUN ["npm", "run", "build"]                                                                  20.2s
 => exporting to image                                                                                  0.2s
 => => exporting layers                                                                                 0.2s
 => => writing image sha256:7cc281e418990a6bf5fc301788dace109f02ad7eca02da5a483ee033eb22c470            0.0s
 => => naming to harbor.freshbrewed.science/freshbrewedprivate/strapidev:v5                             0.0s

Then push (look at my last post where I also show using Dockerhub if you want a free CR).

builder@LuiGi17:~/strapi_k8s2/strapi-project$ docker push harbor.freshbrewed.science/freshbrewedprivate/strapidev:v5
The push refers to repository [harbor.freshbrewed.science/freshbrewedprivate/strapidev]
5e879ec34192: Pushed
654bf0f98772: Pushed
28bc42035366: Pushed
f023094f0304: Layer already exists
f1c4f34bb17c: Layer already exists
89687323f7c8: Layer already exists
5f70bf18a086: Layer already exists
d9c53ce14338: Layer already exists
b76efd4eddd5: Layer already exists
fa5569ec60d1: Layer already exists
b105890ed2f2: Layer already exists
cc2447e1835a: Layer already exists
v5: digest: sha256:fc8db9edd7769428c207d236613e50bd28812c1db912987ed2b766482ef6354a size: 2838

I need to then edit the deploymnet

$ kubectl edit deployments strapi-deployment
deployment.apps/strapi-deployment edited

$ kubectl get deployments strapi-deployment -o yaml | grep image:
        image: harbor.freshbrewed.science/freshbrewedprivate/strapidev:v5

$ kubectl get pods | grep strapi
strapi-deployment-df94c8d6b-nxsz5                        1/1     Running   0                 3m3s

And I can see it was installed by going back to the Marketplace

/content/images/2023/10/strapi-17.png

I’ll clearly need to sort out the query and authorizaton, but we can see it’s responding the query browser (we’ll get to this later in the post)

/content/images/2023/10/strapi-18.png

Adding a Collection Type

In order to see some data, we need to provide some data.

We’ll click “Create New Collection Type”

/content/images/2023/10/strapi2-01.png

And we’ll call it ‘MusicCatalog’

/content/images/2023/10/strapi2-02.png

We’ll add some fields next like AlbumTitle (Text)

/content/images/2023/10/strapi2-03.png

AlbumArtist

/content/images/2023/10/strapi2-04.png

and Year

/content/images/2023/10/strapi2-05.png

When done, don’t forget to save!

/content/images/2023/10/strapi2-06.png

Now, we can go over the Content Manager to add some entries

/content/images/2023/10/strapi2-07.png

I’ll add the last two LPs I picked up

/content/images/2023/10/strapi2-08.png

Next, we need to expose this to the public Role. The UI here has changed over time. I’m using the latest as of today below.

Go to the Public Role and click Edit (Pencil Icon)

/content/images/2023/10/strapi2-09.png

We are going to grant all on the Music Catalog plugin (our new collection)

/content/images/2023/10/strapi2-10.png

And do not forget to hit save in the upper right when done!

We can now see Music Catalog in the Playground context menu popup

/content/images/2023/10/strapi2-11.png

When we search, however, we see no results:

/content/images/2023/10/strapi2-12.png

The reason is we added some albums but left them as “draft”

/content/images/2023/10/strapi2-13.png

Let’s do it together - we’ll verify we cannot see the entries, check their status, publish the drafts and query again:

We can now see proper results

/content/images/2023/10/strapi2-14.png

If we wished to grab just one Album, we could fetch by ID

/content/images/2023/10/strapi2-15.png

We can use mutations to create entries (provided we enabled Create, as we did earlier, on the Public permissions)

mutation musicCatalogs{
   createMusicCatalog(data:{AlbumArtist:"Eric Clapton",AlbumTitle:"Slow Hands",Year:1977}) {
    data { attributes{AlbumTitle}}
  }
}

/content/images/2023/10/strapi2-16.png

This will create an entry in the Catalog, but only in draft state

/content/images/2023/10/strapi2-17.png

If I want to see my Albums including the ‘draft’ ones (preview vs live), I can add a filter:

query{
  musicCatalogs(publicationState:PREVIEW){
    data{
      attributes{
        AlbumTitle
      },
      id
    }
  }
}

/content/images/2023/10/strapi2-18.png

We can use GraphQL to publish:

mutation MusicCatalogs {
  updateMusicCatalog(id:"3", data:{ publishedAt: "2023-10-27T11:18:33.657Z"}) {
    data { attributes {publishedAt}}
  }
}

/content/images/2023/10/strapi2-19.png

This then makes it live

/content/images/2023/10/strapi2-20.png

Authentication

Recall how when we tried to connect to protected routes, it gave us a denied error (Forbidden Access)?

query{
  usersPermissionsRoles{
    data{
      id
    }
  }
}

/content/images/2023/10/strapi2-21.png

This should have given us a JWT

/content/images/2023/10/strapi2-22.png

But I can confirm the REST API also rejects what I know to be the right login, so perhaps there is some new auth bits

$ curl -X POST -H "Accept: text/javascript" -H "Content-Type: application/json" https://strapi.
freshbrewed.science/api/auth/local -d '{"identifier":"isaac@freshbrewed.science", "password":"TheRealPasswordHere"}'
{"data":null,"error":{"status":400,"name":"ValidationError","message":"Invalid identifier or password","details":{}}}

I just needed to confirm the user:

/content/images/2023/10/strapi2-23.png

Then the REST and GraphQL Playground worked

/content/images/2023/10/strapi2-24.png

Summary

We dove into setting up GraphQL in Strapi. We created a collection of albums and populated some data. We looked at querying all albums, some and creating a new entry. We also touched on publishing drafts and creating (and making live) users.

If you are interested in more, you can check out the original Strapi Blog article I used to learn, however it had a few nuances as it was written back in July (e.g. draft posts, unapproved users, and the Roles admin page).

The GraphQL Strapi Documentation is also a great place to learn features of the API.

CMS Strapi Kubernetes GraphQL

Have something to add? Feedback? You can use the feedback form

Isaac Johnson

Isaac Johnson

Cloud Solutions Architect

Isaac is a CSA and DevOps engineer who focuses on cloud migrations and devops processes. He also is a dad to three wonderful daughters (hence the references to Princess King sprinkled throughout the blog).

Theme built by C.S. Rhymes