Quick Introduction to Strapi Headless CMS for Ionic ReactJS Mobile App w/GraphQL
Tags: ionic, react, strapi, graphql
Published: 2021-02-08 07:08:06

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/360yix2ag8zysvo7tps1.png)
##Overview
I started a series on using [strapi.io](https://strapi.io/) as a headless CMS for [Ionic Framework](https://ionicframework.com/docs) application written in ReactJS. In all of the [earlier videos](https://www.youtube.com/playlist?list=PL2PY2-9rsgl0dfKPjXk6bLIIBxhp9vlG5), I was using the REST API to access the content in the CMS and I wanted to try using the GraphQL API that is provided.

>Strapi is the leading open-source headless CMS. It’s 100% Javascript, fully customizable and developer-first.

This post goes along with the [video](https://www.youtube.com/watch?v=VJTzpufik_s&list=PL2PY2-9rsgl0dfKPjXk6bLIIBxhp9vlG5&index=3) I created showing how to refactor the code from the REST API to start using the GraphQL API. 

>This post should be seen as a companion document to the video and source code

- Make Sure to Watch [Video To Setup Server to Support GraphQL](https://youtu.be/VJTzpufik_s)
- REST API Implementation [Video](https://www.youtube.com/playlist?list=PL2PY2-9rsgl0dfKPjXk6bLIIBxhp9vlG5)

##Lets Go
Install libraries we need to get graphql integrated with strapi.
```console
npm install apollo-upload-client
npm i --save-dev @types/apollo-upload-client
npm install graphql @apollo/client
```

Now that we have the libraries, let's set up the client in `index.tsx`

First we import the necessary libraries
```javascript
import { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client";
import { createUploadLink } from "apollo-upload-client";
```

The create the client from `new AplolloClient()`, since we are uploading files we are using the `createUploadLink` function to create the link associated with the strapi server; We will also be using the in memory cache
```javascript
const client = new ApolloClient({
  link: createUploadLink({
    uri: "http://localhost:1337/graphql",
  }),
  cache: new InMemoryCache(),
});
```
Finally, wrap the whole app with the `ApolloProvider` which will give us access to the client in the application.
```javascript
ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById("root")
);
```

### Loading All The ImagePosts
We are going to load all of the posts because they are needed for the first page of the app `Home.tsx`

We need to import the libraries, we're going to use to support the `useQuery` hook
```javascript
import { gql, useQuery } from "@apollo/client";
```
Let's set up the query which was tested in the playground; we use this to get all of the ImagePosts and the properties from the object we need to render in the user interface.
```javascript
const IMAGE_POST_QUERY = gql`
  query getAll {
    imagePosts {
      id
      title
      body
      image {
        name
        id
        url
      }
    }
  }
`;
```
Now we can utilize the useQuery hook to get the data, provide us with some loading information and an error object if necessary.
```javascript
const {
  loading,
  error,
  data,
} = useQuery(IMAGE_POST_QUERY);
```
Now let's move on to the template and start with adding the IonLoading component which uses the `loading` property from above.
```javascript
<IonLoading isOpen={loading} message="Loading..."/>
```
The query returns the data with the property `imagePosts` because that is what I specified in the query; we loop through that property to render the results.
```javascript
<IonList>
  {!loading && data?.imagePosts?.map((p: any) => {
    return (
      <IonItem key={p.id}>
        <IonLabel>
          <h1 className="ion-text-wrap">{p.title}</h1>
          <h2 className="ion-text-wrap">{p.body}</h2>
          <p className="ion-text-wrap">{p.image?.name}</p>
          <div>
            <IonImg
              src={`http://localhost:1337${p.image?.url}`}
            ></IonImg>
          </div>
        </IonLabel>
      </IonItem>
    );
  })}
</IonList>
```

### Adding A New ImagePost
The same process as before when querying the data, we will use when mutating the data. First we define the mutation we will use with the `useMutation` hook and pass it the appropriate parameters.

Like before this is a two-step process, upload the file and then add the post

We will upload the selected image using this upload mutation constant `UPLOAD_MUTATION`
```javascript
const UPLOAD_MUTATION = gql`
  mutation($file: Upload!) {
    upload(file: $file) {
      name
      id
    }
  }
`;
```
Next we are setting the hook up with the name of the method we will use `addImageGQL`. We will need the loading status for the component and then finally we pass in the query. 
```javascript
const [
  addImageGQL, 
  { loading: loadingUpload }
] = useMutation(UPLOAD_MUTATION);
```
In order to call the function and upload the file, we use the `addImageGQL` method like this. The file parameter is from the local state variable we defined to hold the file object returned from the input form.
```javascript
const {
  data: imageData
} = await addImageGQL({ variables: { file } });
```
This will upload the file for us and provide us with the id of the uploaded file to associate with the ImagePost. We can access it like this.
```javascript
imageData.upload.id
```

Now that we have the image in the CMS we can get an id to associate with the imagePost and save the whole document.

First we need the imagePost mutation; a constant `UPLOAD_IMAGE_POST_MUTATION` notice that all of the parameters we need for the mutation are the fields we captured in the input form in `AddItem.tsx`; We also can specify the fields we need to be returned from the mutation.

```javascript
const UPLOAD_IMAGE_POST_MUTATION = gql`
  mutation createImagePost($title: String, $body: String, $image: ID) {
    createImagePost(
      input: { data: { title: $title, body: $body, image: $image } }
    ) {
      imagePost {
        id
        title
        body
        image {
          id
          url
          name
        }
        created_at
      }
    }
  }
`;
```
To upload the post we use the `useMutation` hook and pass along the id of the image and the `title` and `body` from the input form.
```javascript
const [
  addImagePostGQL, 
  { loading: loadingImagePost }
] = useMutation( UPLOAD_IMAGE_POST_MUTATION);
```
here is the use of the hook in action
```javascript
const { data: postData } = await addImagePostGQL({
  variables: {
    title,
    body,
    image: imageData.upload.id,
  },
});
```
At this point, you should be able to see that the document has been added to the strapi CMS.

to handle optimistic load of the imagePosts, meaning load the imagePost in the local cache; we can push the new record into the cache using the following code.
```javascript
const [
  addImagePostGQL, 
  { loading: loadingImagePost }
] = useMutation(
  UPLOAD_IMAGE_POST_MUTATION,
  {
    update: (cache, { data: { createImagePost } }) => {
      const { imagePost } = createImagePost;
      // get the posts from the cache...
      const currentData: any = cache.readQuery({ query: IMAGE_POST_QUERY });
      // add the new post to the cache & write results back to cache
      cache.writeQuery({
        query: IMAGE_POST_QUERY,
        data: {
          imagePosts: [...currentData?.imagePosts, imagePost],
        },
      });
    },
  }
);
```

### Conclusion
As stated above, this is meant to accompany the video so please take a look at the videos in the series, review the document and if it is still not clear, leave a comment.

{% youtube VJTzpufik_s %}