Communications

Communications

APIs for content creation and management such as email, templates, mobile/feed posts, delivery, and more.

Integrating with a Feed

Overview

A feed is a collection of content - or posts - that is displayed on your integration.

The aim of this guide is to demonstrate how to configure a React based web client to make a GraphQL request to bring back information from your feed.

The guide assumes some basic understanding of programming and in particular javascript/typescript and React applications.

Note on Authorization

See the follow guide for details on how to get an Access Token to Authorize access to the GraphQL APIs Authorization

Getting posts from a feed

We can use the getPosts query to retrieve posts from our feed, note that this query uses pagination.

query myQuery {
  getPosts {
    totalCount
    pageInfo {
      startCursor
      endCursor
      hasPreviousPage
      hasNextPage
    }
    edges {
      node {
        id
        author
        body
        title
        status
      }
      cursor
    }
  }
}

This query will return something like the following:

{
  "data": {
    "getPosts": {
      "totalCount": 4,
      "pageInfo": {
        "startCursor": "1uR7priuQj5KxWJ9ucbudJCdyhT",
        "endCursor": "1tLEzOKjpSJXhjqms18MNIbZHhR",
        "hasPreviousPage": false,
        "hasNextPage": true
      },
      "edges": [
        {
          "node": {
            "id": "3b1f3770-d59f-11eb-b0dc-614e46742993",
            "author": null,
            "body": ["<p>test</p>"],
            "title": "Test Video Draft",
            "status": "PUBLISHED"
          },
          "cursor": "1uR7priuQj5KxWJ9ucbudJCdyhT"
        },
        {
          "node": {
            "id": "842cf950-d597-11eb-b5ac-01eae0f19eeb",
            "author": "tara",
            "body": ["<p>nothin</p>"],
            "title": "another test",
            "status": "PUBLISHED"
          },
          "cursor": "1uR0mRfyOqzw5vnSnIKAaiCkXBt"
        },
        {
          "node": {
            "id": "7c36b4c0-d434-11eb-bb01-15bad062969f",
            "author": null,
            "body": ["<p>image draft post</p>"],
            "title": "image draft post",
            "status": "PUBLISHED"
          },
          "cursor": "1uM1timYXLsSQzGKeaI99WSaZRT"
        },
        {
          "node": {
            "id": "c4151a30-d433-11eb-bb01-15bad062969f",
            "author": null,
            "body": ["<p>draft post</p>"],
            "title": "draft post",
            "status": "PUBLISHED"
          },
          "cursor": "1uM1Xqv6DX4bZWakjtYwonKQEFX"
        }
      ]
    }
  }
}

Now we can set up a client to execute this query against the platform api.

GraphQL Client setup

For this guide we're going to use Apollo's GraphQL client but any http client can be used as long as the following headers are set correctly:

  • authorization: bearer token
  • x-channel-id: integration uuid
  • x-channel-version: integration / application version

Following Apollo's guidelines, we can set the headers using setContext.

const authLink = setContext((_, { headers }) => {
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: `Bearer ${getToken()}`,
      'x-channel-id': '123e4567-e89b-12d3-a456-426614174000',
      'x-channel-version': '1.2.3',
    },
  };
});

This is what the completed index.ts file should look like. We can use ApolloProvider to inject the client throughout the application.

  • getToken function requires a valid API token, which can be copied from the developer portal Copy API Token button
  • HttpLink needs to point to either https://api.eu.poppulo-app.com/graphql for the EU or https://api.us.poppulo-app.com/graphql for the US - depending on where your Poppulo enterprise account is hosted.
import { setContext } from '@apollo/client/link/context';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { ApolloClient, ApolloProvider, HttpLink, InMemoryCache } from '@apollo/client';

const httpLink = new HttpLink({
  // ToDo: Confirm which region your enterprise account is hosted in and comment in the correct API you wish to target
  // uri: 'https://api.us.poppulo-app.com/graphql'
  uri: 'https://api.eu.poppulo-app.com/graphql',
});

const authLink = setContext((_, { headers }) => {
  function getToken() {
    //ToDo: For development purposes, an API access can be copied from the developer portal Copy API Token button and pasted here
    return 'insert-copied-api-token-here';
  }

  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: `Bearer ${getToken()}`,
      'x-channel-id': 'react',
      'x-channel-version': '1.2.3',
    },
  };
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

ReactDOM.render(
  <React.StrictMode>
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

Example Application

Now that we know how to configure our client, we can start building out an example react app.

First, run the following command to generate a typescript react app. Further information on this command can be found here.

npx create-react-app my-app --template typescript

An example react application should be generated for you to modify.

We need to install the apollo client dependencies.

yarn add @apollo/client graphql

yarn add --dev @types/graphql

Next we can modify index.tsx file to create the client, and use ApolloProvider to make it available to the rest of the application.

import { setContext } from '@apollo/client/link/context';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { ApolloClient, ApolloProvider, HttpLink, InMemoryCache } from '@apollo/client';

const httpLink = new HttpLink({
  // ToDo: Confirm which region your enterprise account is hosted in and comment in the correct API you wish to target
  // uri: 'https://api.us.poppulo-app.com/graphql'
  uri: 'https://api.eu.poppulo-app.com/graphql',
});

const authLink = setContext((_, { headers }) => {
  function getToken() {
    //ToDo: For development purposes, an API access can be copied from the developer portal Copy API Token button and pasted here
    return 'insert-copied-api-token-here';
  }

  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: `Bearer ${getToken()}`,
      'x-channel-id': 'react',
      'x-channel-version': '1.2.3',
    },
  };
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

ReactDOM.render(
  <React.StrictMode>
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

As we have the client injected through the application via ApolloProvider, we can use useQuery to fetch information from the api.

const TEST_QUERY = gql`
  query myQuery {
    getPosts {
      totalCount
      pageInfo {
        startCursor
        endCursor
        hasPreviousPage
        hasNextPage
      }
      edges {
        node {
          id
          author
          body
          title
          status
        }
        cursor
      }
    }
  }
`;

const { error, loading, data } = useQuery(TEST_QUERY);

The full app.tsx file should look something like the following:

import { gql, useQuery } from '@apollo/client';
import React from 'react';
import logo from './logo.svg';
import './App.css';

function TestComponent() {
  const TEST_QUERY = gql`
    query myQuery {
      getPosts {
        totalCount
        pageInfo {
          startCursor
          endCursor
          hasPreviousPage
          hasNextPage
        }
        edges {
          node {
            id
            author
            body
            title
            status
          }
          cursor
        }
      }
    }
  `;

  const { error, loading, data } = useQuery(TEST_QUERY);

  if (loading) {
    return <p>Loading...</p>;
  }

  if (error) {
    return <p>Error :(</p>;
  }

  // @ts-ignore
  return data.getPosts.edges
    .map((edge) => edge.node)
    .map(({ id, title }) => (
      <div key={id}>
        <p>
          {id}: {title}
        </p>
      </div>
    ));
}

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <TestComponent />
      </header>
    </div>
  );
}

export default App;

With the setup complete - in the project directory - you can now run:

yarn start

This runs the app in the development mode, and you can open http://localhost:3000 to view the app in the browser.

Optional/Advanced: Generate typescript types

To make the query results a bit easier to work with, we can generate a typescript type for them using apollo's CLI client.

yarn add apollo --dev

With a copied API access token for the bearer token, we can run the following command to download the schema. npx apollo client:download-schema schema.graphql --endpoint=https://api.[eu|us].poppulo-app.com/graphql --header="Authorization: Bearer TOKEN"

Run the following command to generate types npx apollo client:codegen --localSchemaFile=schema.graphql --target=typescript

This should create two files for you __generated__/globalTypes.ts and src/__generated__/myQuery.ts.

We can now update our TestComponent to use the new types

function TestComponent() {
  const TEST_QUERY = gql`
    query myQuery {
      getPosts {
        totalCount
        pageInfo {
          startCursor
          endCursor
          hasPreviousPage
          hasNextPage
        }
        edges {
          node {
            id
            author
            body
            title
            status
          }
          cursor
        }
      }
    }
  `;

  const { error, loading, data } = useQuery<myQuery>(TEST_QUERY);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return (
    <div>
      {
        data?.getPosts.edges
          .filter(edge => !!edge)
          .map(edge => edge as myQuery_getPosts_edges)
          .map(edge => edge.node)
          .filter(node => !!node)
          .map(node => node as myQuery_getPosts_edges_node)
          .map(({ id, title }) => (
            <div key={id}>
              <p>
                {id}: {title}
              </p>
            </div>
          ))
      }
    </div>
  );
}

As you can see, we need to do some filtering to ensure that our code is set up to handle undefined values gracefully.

Next steps

For a more complete set of example feeds GraphQL queries to build on, see the following link:

Feeds Example Queries