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.
GraphQL setup
Let’s look up the install command from the marketplace
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
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)
Adding a Collection Type
In order to see some data, we need to provide some data.
We’ll click “Create New Collection Type”
And we’ll call it ‘MusicCatalog’
We’ll add some fields next like AlbumTitle (Text)
AlbumArtist
and Year
When done, don’t forget to save!
Now, we can go over the Content Manager to add some entries
I’ll add the last two LPs I picked up
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)
We are going to grant all on the Music Catalog plugin (our new collection)
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
When we search, however, we see no results:
The reason is we added some albums but left them as “draft”
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
If we wished to grab just one Album, we could fetch by ID
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}}
}
}
This will create an entry in the Catalog, but only in draft state
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
}
}
}
We can use GraphQL to publish:
mutation MusicCatalogs {
updateMusicCatalog(id:"3", data:{ publishedAt: "2023-10-27T11:18:33.657Z"}) {
data { attributes {publishedAt}}
}
}
This then makes it live
Authentication
Recall how when we tried to connect to protected routes, it gave us a denied error (Forbidden Access)?
query{
usersPermissionsRoles{
data{
id
}
}
}
This should have given us a JWT
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:
Then the REST and GraphQL Playground worked
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.