Building a Sell app using OAuth 2.0 - Part 5: Getting data from the Mailchimp API
At this stage of the tutorial series, you should have registered your app with Mailchimp and have OAuth set up in your app. In Mailchimp, you created at least one audience with a subscriber. The subscriber's email address should match the email of your person contact in Zendesk Sell.
In this tutorial, you'll add extra features to your app. The app will make authorized requests to the Mailchimp API to get audiences and then display them in a list.
This tutorial covers the following steps:
- Getting a person email address from Sell
- Working with authorized requests
- Retrieving a server prefix from Mailchimp
- Fetching audiences from Mailchimp
This tutorial is part of a series on building a Zendesk app:
- Part 1: Laying the groundwork
- Part 2: Installing the app in Zendesk Sell
- Part 3: OAuth 2.0 setup )
- Part 4: Creating audiences in Mailchimp
- Part 5: Getting data from the Mailchimp API - YOU ARE HERE
Getting a person email address from Sell
You'll be retrieving audiences that a person contact subscribes to using Mailchimp lists endpoint.
GET https://server.api.mailchimp.com/3.0/lists?email=<EMAIL>
First, you'll get a person's email address from Sell and pass it as a query parameter. You could use the useSellContactEmail hook, but since the app supports one location (person_card), a simplified version can be created.
The useClientGet hook provided by the Sell ZAF app toolbox package will be used. It uses the Apps framework client.get() method to get data asynchronously for a given path.
The useClientGet hook returns an object with data, error, and feedback properties which have different values depending on the state of a request. The structure works well with the <ResponseHandler/> component mentioned in Reviewing the template files in part 2 of the tutorial series.
If a request isn’t completed yet, the hook returns:
{data: null, error: null, feedback: {status: "loading"}}
If the request is completed successfully, it returns response data and updates a feedback status:
{data: {firstName: "Ewen",lastName: "Marin",email: "[email protected]",name: "Ewen Marin",....}error: nullfeedback: {status: "success"}}
Get the email address from Sell
-
Restart the app and the ZCLI server to be able to test it locally. For more information, refer back to Developing the app locally in the Part 2: Installing the app in Zendesk Sell.
Note: In Part 3: OAuth 2.0 setup , you added an access token as an OAuth parameter to the manifest.json file. If you are requested to type it while running the ZCLI server, ignore it and click Enter. It won’t affect your app.
In the Apps Sell API for person_card location, you can access the contact object. One of the contact object properties is an email address you retrieve with
client.get('contact.email'). Try this out using the hook. -
In the EntryView.tsx file (src/EntryView.tsx), replace the
<EntryView/>component with the following:export const EntryView = () => {useClientHeight(230)const contactEmailResponse = useClientGet('contact.email')return (<Grid gutters={false} className={css.App}><Row><ResponseHandlerresponse={contactEmailResponse}loadingView={<Loader />}errorView={<div>Something went wrong!</div>}emptyView={<div>There's nothing to see yet.</div>}>{([email]: [string]) => (<Col textAlign="center"><Header contactEmail={email} /><ContentView /></Col>)}</ResponseHandler></Row></Grid>)} -
Save the file and refresh the app in your web browser. The email should be still there.
Working with authorized requests
Since you’ll be calling the Mailchimp API a few times, this logic will be extracted to a new helper method. We can leverage the existing helper useClientRequest and pass extra options to make an authorized request.
useClientRequest makes an HTTP request using the Apps framework. It uses the client.request() method which is the recommended method to make requests which are proxied to interpolate OAuth access tokens. It takes the URL of the resource as the first argument in the request. If you need to send additional parameters with the request, you can define them as a second argument.
The structure of the response is the same as for the useClientGet hook that you're using in the Getting a person email address from Sell.
Create an authorized request
-
Create a hooks folder in the src directory.
-
Create a useClientAuthorizedRequest.tsx file inside it. Add the following code to the file and save it:
import {useClientRequest, Response} from '@zendesk/sell-zaf-app-toolbox'/* parameter of type 'oauth' should exist in the manifest.json file{"name" : "access_token","type": "oauth"}*/export default function useClientAuthorizedRequest<T extends {}>(url: string,options: object = {},dependencies?: any[],): Response<T> {const response = useClientRequest<T>(url,{secure: true,headers: {authorization: 'OAuth {{setting.access_token}}'},dataType: 'json',contentType: 'application/json',...options,},dependencies,)return response}
As discussed in Part 3: OAuth 2.0 setup in the "Configuring an app in the manifest" section, you have to include the following properties to a call request to a third-party service - secure: true and authorization header set to OAuth {{setting.access_token}}.
With this setup, you can make your first request to the Mailchimp API.
Retrieving a server prefix from Mailchimp
The created useClientAuthorizedRequest hook will be used to get information about the user who granted OAuth access. Specifically, you get the user's server prefix which is needed to make calls to the Mailchimp API on the user’s behalf. This prefix will change from user to user. To retrieve the server prefix, a GET request is sent to Mailchimp's metadata endpoint:
https://login.mailchimp.com/oauth2/metadata
Retrieve server prefix from Mailchimp
-
Create another hook in the useMailchimpMetadata.tsx file /src/hooks/ directory with the following content:
import {Response} from '@zendesk/sell-zaf-app-toolbox'import useClientAuthorizedRequest from './useClientAuthorizedRequest'import {LoginMetadata} from '../types'export default function useMailchimpMetadata(): Response<LoginMetadata> {return useClientAuthorizedRequest<LoginMetadata>('https://login.mailchimp.com/oauth2/metadata',{},[],)} -
Since you're using TypeScript in the project, create a types.ts file in the src/ directory and add the following types so the hook is statically typed.
export interface Login {email: stringavatar?: anylogin_id: numberlogin_name: stringlogin_email: string}export interface MailchimpMeta {dc: stringrole: stringaccountname: stringuser_id: numberlogin: Loginlogin_url: stringapi_endpoint: string}export interface LoginMetadata {data?: MailchimpMeta} -
Call the
useMailchimpMetadatahook from the<EntryView/>component.// other importsimport useMailchimpMetadata from './hooks/useMailchimpMetadata'export const EntryView = () => {... // other hooksconst mailchimpMetadataResponse = useMailchimpMetadata() // server prefix requestreturn ...} -
Save the files.
-
Go to Sell and open the Developer Tools by using the one of the shortcuts depending on your browser.
- Google Chrome: Option + ⌘ + J (on macOS), or Shift + CTRL + J (on Windows/Linux)
- Firefox: Option + ⌘ + I (on macOS), or Shift + CTRL + I or F12 (on Windows/Linux)
-
Click the Network tab to observe requests.
-
Refresh the app. When the app is loaded, look for the Mailchimp metadata request in the Network tab. The request should succeed with a status 200 response.
-
Switch to the Preview tab to check the response. Look for the
api_endpoint.
The server prefix will be used in the next section to fetch audiences.
Fetching audiences from Mailchimp
We have all the information required to fetch audiences for a given person.
Fetch audiences from Mailchimp
-
Create useAudiences.tsx file in the /src/hooks/ directory and add the following code:
import {Response} from '@zendesk/sell-zaf-app-toolbox'import useClientAuthorizedRequest from './useClientAuthorizedRequest'import {MailchimpLists} from '../types'const useAudiences = ({email,apiEndpoint,}: {email: stringapiEndpoint: string}): Response<MailchimpLists> => {const url = `${apiEndpoint}/3.0/lists?email=${email}&sort_field=date_created`return useClientAuthorizedRequest<MailchimpLists>(url, {}, [])}export default useAudiencesThe
useAudienceshook takesemailandapiEndpoint(server prefix) which are required to compose the correct lists url. -
Add the following types to the types.ts file:
export interface Constraints {may_create: booleanmax_instances: numbercurrent_total_instances: number}export interface ListStats {member_count: numberunsubscribe_count: numbercleaned_count: numbermember_count_since_send: numberunsubscribe_count_since_send: numbercleaned_count_since_send: numbercampaign_count: numbercampaign_last_sent: stringmerge_field_count: numberavg_sub_rate: numberavg_unsub_rate: numbertarget_sub_rate: numberopen_rate: numberclick_rate: numberlast_sub_date: anylast_unsub_date: string}export interface Contact {company: stringaddress1: stringaddress2: stringcity: stringstate: stringzip: stringcountry: stringphone: string}export interface CampaignDefaults {from_name: stringfrom_email: stringsubject: stringlanguage: string}export interface Link {rel: stringhref: stringmethod: stringtargetSchema?: stringschema?: string}export interface List {id: stringweb_id: numbername: stringcontact: Contactpermission_reminder: stringuse_archive_bar: booleancampaign_defaults: CampaignDefaultsnotify_on_subscribe: stringnotify_on_unsubscribe: stringdate_created: Datelist_rating: numberemail_type_option: booleansubscribe_url_short: stringsubscribe_url_long: stringbeamer_address: stringvisibility: stringdouble_optin: booleanhas_welcome: booleanmarketing_permissions: booleanmodules: any[]stats: ListStats_links: Link[]}export interface MailchimpLists {lists: List[]total_items: numberconstraints: Constraints_links: Link[]}Next, you'll to call the
useAudienceshook in a new<AudiencesList/>component which is responsible for displaying audiences from the lists request. Take a look at JSON success example response to get familiar with the data structure.We'll be iterating audiences, showing an audience name (
audience.name) and a the number of subscribers (audience.stats.member_count) for a single item. -
Create
AudiencesList.tsxfile in src/components/ folder with the following content:import * as React from 'react'import {Row} from '@zendeskgarden/react-grid'import {ResponseHandler} from '@zendesk/sell-zaf-app-toolbox'import ListStroke from '@zendeskgarden/svg-icons/src/16/clipboard-list-stroke.svg'import useAudiences from '../hooks/useAudiences'import {List} from '../types'import css from '../App.css'interface AudiencesListProps {email: stringapiEndpoint: string}const Audience = ({audience}: any) => {return (<div className={css.audience}><div className={css.title}>{audience.name}</div><p>Member count: {audience.stats.member_count}</p></div>)}const AudiencesList = ({email, apiEndpoint}: AudiencesListProps) => {const audiencesResponse = useAudiences({email, apiEndpoint})return (<><Row justifyContent="center" className={css.header}><div className={css.icon}><ListStroke /></div><div className={css.title}>Audiences</div></Row><Row><ResponseHandlerresponse={audiencesResponse}errorView={<div>Something went wrong!</div>}emptyView={<div>There's nothing to see yet.</div>}>{([{lists}]) => {return lists.map((list: List, index: number) => (<Audience key={index} audience={list} />))}}</ResponseHandler></Row></>)}export default AudiencesList -
Add the following rules to the App.css file to style the audiences list:
.audience {border-bottom: solid 1px var(--zd-color-grey-300);overflow: hidden;display: block;width: 100%;padding: var(--zd-spacing-sm);}.icon {margin-right: var(--zd-spacing-xs);} -
Update the
<EntryView/>component in src/EntryView.tsx to display the audiences list as well as deliver the subscriber email and your server prefix:// other importsimport {MailchimpMeta} from './types'import AudiencesList from './components/AudiencesList'export const EntryView = () => {... // other hooksconst mailchimpMetadataResponse = useMailchimpMetadata()return (<Grid gutters={false} className={css.App}><Row><ResponseHandlerresponses={[contactEmailResponse, mailchimpMetadataResponse]}loadingView={<Loader />}errorView={<div>Something went wrong!</div>}emptyView={<div>There's nothing to see yet.</div>}>{([email, mailchimpMetadata]: [string, MailchimpMeta]) => (<Col><AudiencesListemail={email}apiEndpoint={mailchimpMetadata.api_endpoint}/></Col>)}</ResponseHandler></Row></Grid>)}The
<ResponseHandler/>component takes an array of responses and display its children when all requests are completed. -
Go to your web browser and refresh the app in your Sell instance. You should see a list of audiences to which your person contact in Sell subscribes.
Congratulations! You’ve created the app with a working OAuth flow.
Next steps
The best way to learn is to plan, design, and build your own apps. You can use any of the following resources:
- Getting started - A quick overview of the Apps framework
- Setting up new apps - How to create starter files for your apps with ZCLI or use the ZAF React Skeleton for Sell Apps
- Using the Apps framework - A concise developer guide
- Deploying apps - Information on branding, uploading, and localizing your apps
- ZAF Client API - A reference of the ZAF JavaScript client
- ZAF Core API - A reference of core events, actions, and properties available in all locations in all products that support the Zendesk Apps framework
- ZAF Sell API - A reference of the app locations, properties, and events you can use in apps running in Zendesk Sell
- ZAF App Toolbox - A package which delivers a bunch of useful methods, hooks, and components to help you build React apps integrated with Zendesk Sell quicker and with less effort. It uses the Zendesk Apps framework (ZAF) Client .
You can also look for answers or ask questions in the Zendesk Apps framework (ZAF) community.