LogoLogo
  • Getting Started
    • Pandium Documentation
    • What is Pandium?
      • The Pandium Platform
      • What Companies Use Pandium For
      • Platform Structure
      • Users of Pandium
    • Anatomy of an Integration
      • Run Triggers
      • PANDIUM.yaml
        • Schema
        • UiSchema
        • Dynamic Configurations
        • Dependent Selector Configurations
      • Environment Variables
        • Context: StdOut
        • Logging (StdErr)
    • Key Terminology
    • Pandium Integration Tutorial
      • Pokémon of the Day, Part 1
        • Create App in Slack to get Credentials
        • Create Integration on the Pandium Integration Hub
        • Make a Tenant
        • Write the Integration in Typescript
          • Add the .env
          • Configure the PANDIUM.yaml
          • Check the Customized Connection Settings Page
          • Add the Pokémon client
          • Add the Slack Client
          • Add the pokemonSync flow
          • Run Normal Sync on the Tenant
        • Update the Tenant Schedule
      • Pokémon of the Day, Part 2
        • Update the PANDIUM.yaml
        • Check the Updated Connection Settings Page
        • Add Dynamic Configs
        • Run Init Sync on the Tenant
        • Update the pokemonSync flow
        • Run updated Normal Sync on the Tenant
  • Integration Hub
    • Setting Up Source Control
    • Creating An Integration
      • Getting Started with Creating an Integration
      • Demo Video: Creating an Integration With Pandium
    • Managing Internal Integrations
    • Creating a Tenant In the Integration Hub
    • Managing and Updating Tenants
    • Managing and Updating Releases
    • Managing External Integrations
    • Managing Tenant Connection Settings
    • Creating Users
    • Managing Users
    • Administrator Settings
    • Site Metrics
  • Marketplaces
    • Integration Onboarding Experiences Overview
      • Embedding the In-App Marketplace
      • Embedding the Integration Install Only
      • Embedding Auth-Only Connections
    • Customizing the JWT
    • Marketplace Settings
    • App Installation Options
    • Flags, Tags, and Categories
    • Public Gallery
  • Connectors
    • Connectors 101
      • Active Campaign
      • Afterpay
      • AfterShip
      • Airship
      • Alasco
      • Algolia
      • Amadeus
      • Amazon
      • Ankored
      • Apollo.io
      • AppSignal
      • AskNicely
      • Assembled
      • Attentive
      • AWS
      • Azure Devops
      • Azure Personal Access Token
      • Bandcamp
      • Bazaarvoice
      • BigCommerce
      • Bitbucket
      • Booker
      • Box
      • Braze
      • Brightpearl
      • Campaign Monitor
      • Capabl
      • Chargebee
      • Chargify
      • Chubb
      • Cin7
      • Coach Packet
      • ConnectSports
      • Constant Contact
      • Customer Thermometer
      • Datadog
      • Datev
      • Delighted
      • DHL
      • DHL Unified
      • Domo
      • Dotdigital
      • Drip
      • Dropbox
      • Dynamic Yield
      • Easyship
      • Eloqua
      • Emotive
      • Endear
      • Envision
      • eTip
      • EvaluAgent
      • Exact Online
      • eZCom
      • Fabric
      • Facebook
      • Falcon.io
      • Famer
      • Fedex
      • Field Nation
      • Finch
      • Fivetran
      • Fleetio
      • Flowcode
      • Follow Up Boss
      • Fortnox
      • Foundation Software
      • Fulfil
      • GetResponse
      • GitHub
      • GitLab
      • Gladly
      • Google
      • Google Service Account
      • Gooten
      • Gorgias
      • Greenhouse.io
      • Happy Returns
      • HootSuite
      • Hubspot
      • Image Relay (Basic)
      • Imgur
      • Iterable
      • Jasper
      • JDP
      • Justuno
      • Kentico Kontent
      • Klaus
      • Klaviyo
      • Kombo
      • Kustomer
      • kvCORE
      • LeagueApps
      • Lessonly
      • Lexoffice
      • Linga rOS
      • Linnworks
      • Listrak
      • Loop Returns
      • LoyaltyLion
      • Lucid Travel
      • Lytx
      • MaestroQA
      • Magento (OAuth)
      • Mailchimp
      • Marketo
      • Medallia
      • Microsoft Entra
      • Mintsoft
      • NCSA Athletic Recruiting
      • Netomi
      • Netsuite
      • Nicereply
      • Nylas
      • Omnisend
      • OnPay
      • OnRamp
      • Ontraport
      • Optimizely Data Platform (ODP)
      • Pandium
      • Personio
      • PayCom
      • Perspective
      • Player's Health
      • Playvox
      • Pleo
      • Postscript
      • Promoter
      • Quickbooks Online
      • Qualtrics
      • Recart
      • ReCharge
      • Recurly
      • Returnly
      • ReverseLogix
      • Rydership (formerly Whiplash)
      • Sage Intacct
      • SailThru
      • Salesforce
      • Salesforce Marketing Cloud
      • Salesforce Pardot
      • SendGrid
      • Sendlane
      • SevenRooms
      • SFTP
      • ShipBob
      • ShipHero
      • ShipMonk
      • Shippo
      • Shipstation
      • Shopify
      • Skubana
      • Slack (OAuth2)
      • SmartrMail
      • Smartrr
      • Smartvatten
      • Smile.io
      • Solidus
      • Springbig
      • Square
      • Square (Sandbox)
      • Stamped
      • Stella Connect
      • SugarCRM
      • Swell
      • Talkable
      • TeamGenius
      • Tether
      • Thankful
      • TikTok
      • Trinet-B2B Test
      • Triple Whale
      • TrustPilot
      • Twilio
      • Twitter
      • Unbabel
      • UPS
      • Upscribe
      • USPS
      • Visma e-conomic
      • Visma.net
      • Walmart
      • Wix
      • WorkMax
      • Xero (OAuth)
      • Yardstik
      • Yotpo
      • Zendesk (Support)
      • Zingtree
      • Zonos
  • Partners
    • Inviting Partners
    • Partner Form
    • Integration Form
    • Managing Partners
    • Partner User Guide
  • Reference
    • Pandium API
    • Pandium CLI
    • FAQ
    • Sample Integrations
    • Repository Permissions
      • Bitbucket
      • Azure
      • GitLab
      • GitHub
    • Email Support
Powered by GitBook
On this page

Was this helpful?

  1. Getting Started
  2. Pandium Integration Tutorial
  3. Pokémon of the Day, Part 1
  4. Write the Integration in Typescript

Add the pokemonSync flow

You have clients that talk to both APIs, so put them together to start sending educational Pokémon messages via Slack.

A Pandium integration can be run in normal mode or init mode. The pokemonSync flow is for normal mode.

The goal in this flow is to send a Slack message about a new Pokémon each day. To do this we will need to:

  1. Add the file for this new flow:

    Your file structure should now look like this:

  ├── build 
  ├── node_modules 
  ├── src
  │  ├── processLogic
  │  │  └── pokemonSync.ts
  │  ├── index.ts
  │  └── lib.ts
  ├── .env
  ├── package.json
  ├── PANDIUM.yaml
  └── tsconfig.json
  1. Within src/processLogic/pokemonSync.ts add the shell of an asynchronous pokemonSync function.

export const pokemonSync = async () => {
    console.error('------------------------POKEMON SYNC------------------------')
}
  1. Within src/index.ts import pokemonSync and invoke it within the run function when the run mode is normal.

The src/index.ts should now look something like this:

import * as dotenv from 'dotenv'
dotenv.config()
import { WebClient } from '@slack/web-api'
import Pokedex from 'pokedex-promise-v2'
import { Config, Secret, Context } from './lib.js'
import { pokemonSync } from './processLogic/pokemonSync.js'

const run = async () => {
    const context = new Context()
    const secrets = new Secret()
    const config = new Config()

    console.error(`This run is in mode: ${context['run_mode']}`)
    console.error('------------------------CONFIG------------------------')
    console.error(config)

    console.error('------------------------CONTEXT------------------------')
    console.error(context)

    const pokeClient = new Pokedex()
    const slackClient = new WebClient(secrets.slack_token)
   
    if (context.run_mode === 'normal') {
        await pokemonSync()
    } 
}

run().then(
    () => {},
    () => {
        process.exitCode = 1
    }
)
  1. Run npm run build && npm run start, and you should see the following logged:

> pokemon-of-the-day@1.0.0 start
> node build/src/

This run is in mode: normal
------------------------CONFIG------------------------
Config {}
------------------------CONTEXT------------------------
Context { run_mode: 'normal' }
------------------------POKEMON SYNC------------------------
  1. Fetch a Pokémon by doing the following:

The pokemonSync.ts file should look something like this:

import Pokedex from 'pokedex-promise-v2'

export const pokemonSync = async (
    pokeClient: Pokedex
) => {
    console.error('------------------------POKEMON SYNC------------------------')
    const nextPokemonId = 247
    const pokemonOfTheDay = await pokeClient.getPokemonByName(nextPokemonId)
    console.error(pokemonOfTheDay)
}
  1. Run npm run build && npm run start.

You should see the same information logged as before - except that now a large Pokémon object has also been printed. This confirms the Pokémon client within pokemonSync is working, so you can remove the console.error(pokemonOfTheDay).

  1. Add a function to transform the pokemonOfTheDay into a Slack message.

Here is one way transformations.ts could look:

import { Pokemon } from 'pokedex-promise-v2'
import { ChatPostMessageArguments } from '@slack/web-api'

export const pokemonToSlackMessage = (
    pokemon: Pokemon,
    channel: string
): ChatPostMessageArguments => {
    const abilities = pokemon.abilities
        .map((ability) => ability.ability.name)
        .join(', ')
    const text = `The Pokemon of the Day is *${pokemon.name}*!
        *Abilties:* ${abilities}
        *Base Experience:* ${pokemon.base_experience}
        *Height:* ${pokemon.height}
        *Weight:* ${pokemon.weight}`
    const message: ChatPostMessageArguments = {
        channel: channel,
        text: text,
        blocks: [
            {
                type: 'section',
                text: {
                    type: 'mrkdwn',
                    text: text,
                },
            },
        ],
    }

    if (pokemon.sprites.back_default) {
        message.blocks?.unshift({
            type: 'image',
            image_url: pokemon.sprites.back_default,
            alt_text: `${pokemon.name} sprite`,
        })
    }
    return message
}
  1. Within pokemonSync use pokemonToSlackMessage and slackClient.chat.postMessage to send a message to each of the Academy's Pokémon trainers.

The pokemonSync.ts file should look something like this:

import Pokedex from 'pokedex-promise-v2'
import { WebClient } from "@slack/web-api"
import {pokemonToSlackMessage} from '../transformations.js'

export const pokemonSync = async (
    pokeClient: Pokedex,
    slackClient: WebClient
) => {
    console.error('------------------------POKEMON SYNC------------------------')
    const nextPokemonId = 247
    const pokemonOfTheDay = await pokeClient.getPokemonByName(nextPokemonId)

    const slackMemberIds = ['<YOUR-SLACK-MEMBER-ID>']

    for (const slackID of slackMemberIds){
        const slackMessage = pokemonToSlackMessage(
            pokemonOfTheDay,
            slackID
        )
        await slackClient.chat.postMessage(slackMessage)
    }
}
  1. Run npm run build && npm run start. You should get a Slack message about the Pokémon of the Day!

We're not quite done though. If you try running npm run start again you will get another Slack message about the same Pokémon. One of the Academy's requests is that we won't repeat Pokémon.

To accomplish this goal, we will use context to learn which Pokémon have already been used.

  1. Alter the integration so that it prints a standard out during a normal sync.

  2. Run npm run build && npm run start.

You should get another slack message about that same Pokémon. However the logs now include the standard out, which should look something like this {"last_pokemon_id":247}.

  1. Add a standard out to your .env.

PAN_CTX_LAST_SUCCESSFUL_RUN_STD_OUT= '{"last_pokemon_id":247}'
  1. Use that standard out in pokemonSync to ensure the Pokémon of the day is not repeated.

Your pokemonSync.ts should look like this:

import Pokedex from 'pokedex-promise-v2'
import { WebClient } from "@slack/web-api"
import {pokemonToSlackMessage} from '../transformations.js'
import { Context } from '../lib.js'

export const pokemonSync = async (
    pokeClient: Pokedex,
    slackClient: WebClient,
    context: Context
) => {
    console.error('------------------------POKEMON SYNC------------------------')
    
    let lastPokemonId = 0
    if (context.last_successful_run_std_out) {
        const lastStdOut = JSON.parse(context.last_successful_run_std_out)
        lastPokemonId = Number(lastStdOut.last_pokemon_id) || 0
    }
    
    const nextPokemonId = lastPokemonId + 1
    const pokemonOfTheDay = await pokeClient.getPokemonByName(nextPokemonId)

    const slackMemberIds = ['<YOUR-SLACK-MEMBER-ID>']

    for (const slackID of slackMemberIds){
        const slackMessage = pokemonToSlackMessage(
            pokemonOfTheDay,
            slackID
        )
        await slackClient.chat.postMessage(slackMessage)
    }

    return {last_pokemon_id: nextPokemonId}
}
  1. Run npm run build && npm run start. You should get another Slack message about a new Pokémon!

The logs should look like this:

> pokemon-of-the-day@1.0.0 start
> node build/src/

This run is in mode: normal
------------------------CONFIG------------------------
Config {}
------------------------CONTEXT------------------------
Context {
  run_mode: 'normal',
  last_successful_run_std_out: '{"last_pokemon_id":247}'
}
------------------------POKEMON SYNC------------------------
{"last_pokemon_id":248}

Notice the following about the logs:

  • The context now has a the last run's standard out.

  • The ID printed to the standard out for this run is greater than the ID from the last run's standard out.

The final step is to see what this all looks like when it is run on Pandium!

Last updated 1 year ago

Was this helpful?

Pass nextPokemonId to the pokeClient.getPokemonByNamemethod to fetch a Pokémon by ID, because state "Any function with the designation 'ByName' can also be passed an integer ID."

Review for the postMessage endpoint and the Pokemon Typescript interface to fill out the pokemonToSlackMessage transformation function.

Pandium stores the of each tenant's last successful normal sync, so it can be accessed as an during the next run.

Your pokemonSync.ts should loook like the one . In fact, all your integration files should match all the ones in .

the docs for the Pokémon library
these Slack Web API docs
here
this repository at this commit
standard out
environmental context variable