DEV Community

Cover image for Developing a Salesforce integration, quickly & easily
Anurag Allena for Alloy Automation

Posted on

Developing a Salesforce integration, quickly & easily

This post was originally published at runalloy.com.

If you’ve ever built a CRM integration, I’m guessing you didn't love it 😅

At Alloy, we’re working hard on building a Unified API solution that helps developers ship major integrations faster (think CRMs, Commerce Platforms, ERPs). Today, we’d love for you to try it out for free and let us know what you think.

We’ve put together this tutorial guiding you through building a CRM integration using Next.js and Alloy. You’ll learn how to add Alloy functionality to a pre-built Next.js project, enable a connection to a CRM system like Salesforce, get a list of contacts from the CRM, and write new contacts to the CRM. No worries if you’re new to Next.js — it’s built on React and should be familiar for Javascript developers.

Prerequisites

  • Node.js (version 12 or higher)
  • Basic knowledge of React and Next.js
  • Text editor or IDE
  • Salesforce account for testing (optional)
  • Free Alloy Unified API account (you can sign up here)

We’ve provided a step-by-step guide on how to build this use case, including how to integrate our SDKs and APIs into your application so you can ship integrations.

And so, with some combination of excitement, nerves, and eagerness to get feedback, here’s a link to the repo in GitHub: unified-crm-tutorial

You'll find the step-by-step tutorial below. Your support means everything to us, so if you like what you see, please consider giving us a star/follow on GitHub or check us out on ProductHunt.

PS — if you want to build this live with us, we’re going to be walking through the tutorial on Jan. 25, where you’ll have the opportunity to follow along and ask questions. You can sign up for that here!

Understanding the Repository Structure

  • Start branch: Where you’ll start. Contains the basic project setup and components without complete Alloy integration — you’ll build that.
  • Main branch: Use this as a reference. It contains the completed project with full Alloy integration.

Getting Started

1. Clone the starting repository
Clone the provided repository and switch to the start branch:

git clone https://github.com/your-repository/practice-crm-app.git
cd practice-crm-app
git checkout start
Enter fullscreen mode Exit fullscreen mode

2. Set up environment variables
You’ll need to set up your Alloy User ID and API Key as environment variables before proceeding. Replace the placeholders with your actual Alloy credentials:

export ALLOY_USER_ID='your-alloy-user-id'
export ALLOY_API_KEY='your-alloy-api-key'
Enter fullscreen mode Exit fullscreen mode

3. Install dependencies
Install the dependencies for this project:

npm install

4. Run the application
Start up the application — you’ll see the basic UI in its initial state:

npm run dev

Open http://localhost:3000 in your browser to view the application. The tutorial UI will show three steps — connecting the CRM, getting a list of contacts, and creating new contacts. Each corresponds to a Javascript Component that you will complete.

Image description

Establishing a Connection

To create a connection to a 3rd party from your app, Alloy requires that we fetch a short-lived JWT token for an Alloy user and pass the JWT to the frontend SDK via alloy.authenticate().

1. Modify token.js API Route:

Update the token.js file in the pages/api directory to generate a JWT token using Alloy's API.

Updated Code for token.js:

// pages/api/token.js
export default async function handler(req, res) {
  const YOUR_API_KEY = process.env.ALLOY_API_KEY;
  const userId = process.env.ALLOY_USER_ID;

  try {
    const response = await fetch(`https://embedded.runalloy.com/2023-12/users/${userId}/token`, {
      headers: {
        'Authorization': `Bearer ${YOUR_API_KEY}`,
        'Accept': 'application/json'
      }
    });
    const data = await response.json();
    res.status(200).json({ token: data.token });
  } catch (error) {
    console.error('Error generating JWT token:', error);
    res.status(500).json({ error: 'Error generating JWT token' });
  }
}

Enter fullscreen mode Exit fullscreen mode

Note:

  • Ensure you have set ALLOY_API_KEY and ALLOY_USER_ID in your environment variables.
  • This code fetches a JWT token from Alloy and returns it in the response. This token is required for authenticating with the Alloy SDK.

You’ll need this for the next step, where you'll integrate the JWT token generation with the front-end ConnectApp.js component.

2. Set up ConnectApp.js:

Implement Alloy authentication logic in the ConnectApp.js file within the src/app/components directory.

Updated code for ConnectApp.js:

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import Alloy from 'alloy-frontend';
import styles from './css/ConnectApp.module.css';

export default function ConnectApp({ onConnectionEstablished }) {
  const [alloy, setAlloy] = useState(null);

  useEffect(() => {
    setAlloy(Alloy());
  }, []);

  const fetchTokenAndAuthenticate = async () => {
    if (!alloy) {
      console.error('Alloy SDK not initialized');
      return;
    }

    try {
      const response = await axios.get('/api/token');
      alloy.setToken(response.data.token);
      alloy.authenticate({
        category: 'crm',
        callback: (data) => {
          if (data.success) {
            localStorage.setItem('connectionId', data.connectionId);
            onConnectionEstablished(data.connectionId);
          }
        }
      });
    } catch (error) {
      console.error('Error fetching JWT token:', error);
    }
  };

  return (
    <div className={styles.connectContainer}>
      <button className={styles.connectButton} onClick={fetchTokenAndAuthenticate}>
        Connect App
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Note:

  • The useEffect hook initializes the Alloy SDK.
  • The (aptly named) fetchTokenAndAuthenticate function fetches the JWT token from the /api/token route and uses it to authenticate with Alloy.
  • Upon successful authentication, the connection ID is stored and the onConnectionEstablished callback is triggered.

Once authenticated, it allows further actions such as listing and creating contacts.

Implementing Contacts API Routes

1. Update contacts.js API Route:

Refactor the contacts.js file in the pages/api directory to manage fetching and creating contacts using Alloy's API.

Here’s what the initial code template looks like:

export default function handler(req, res) {
  console.log('Contacts API endpoint hit. Implement Alloy contacts functionality here.');
  res.status(200).json({ message: 'This is where Alloy contacts functionality will be implemented.' });
}

Enter fullscreen mode Exit fullscreen mode

And here’s the updated code for contacts.js with Alloy API integration:

// pages/api/contacts.js
export default async function handler(req, res) {
  const YOUR_API_KEY = process.env.ALLOY_API_KEY;
  const connectionId = req.query.connectionId;

  if (!connectionId) {
    return res.status(400).json({ error: 'ConnectionId is required' });
  }

  const headers = {
    'Authorization': `bearer ${YOUR_API_KEY}`,
    'Accept': 'application/json'
  };

  switch (req.method) {
    case 'GET':
      try {
        const response = await fetch(`https://embedded.runalloy.com/2023-12/one/crm/contacts?connectionId=${connectionId}`, { headers });
        const data = await response.json();
        res.status(200).json(data);
      } catch (error) {
        console.error('Error fetching contacts:', error);
        res.status(500).json({ error: 'Error fetching contacts' });
      }
      break;

    case 'POST':
      try {
        const response = await fetch(`https://embedded.runalloy.com/2023-12/one/crm/contacts?connectionId=${connectionId}`, {
          method: 'POST',
          headers: { ...headers, 'Content-Type': 'application/json' },
          body: JSON.stringify(req.body)
        });
        const data = await response.json();
        res.status(200).json(data);
      } catch (error) {
        console.error('Error creating contact:', error);
        res.status(500).json({ error: 'Error creating contact' });
      }
      break;

    default:
      res.setHeader('Allow', ['GET', 'POST']);
      res.status(405).end(`Method ${req.method} Not Allowed`);
  }
}

Enter fullscreen mode Exit fullscreen mode

Note:

  • This API route handles GET requests for fetching existing contacts and POST requests for creating new contacts.
  • The switch statement directs the request based on the method (GET or POST).
  • Both requests use Alloy's API and require a valid connectionId.
  • The headers include the necessary authorization and accept headers for the API requests.

This API route is crucial for managing contacts in the CRM integration. It interacts with Alloy's API to retrieve and store contact information.

Setting Up Contact Components

1. Configure ContactList.js:

Update ContactList.js in the src/app/components directory to interact with your contacts.js API route for fetching contacts.

Here’s what the initial code template looks like:

import React, { useState } from 'react';
import styles from './css/ContactList.module.css';

export default function ContactList({ connectionId }) {
  const [contacts] = useState([]); // Placeholder array for contacts
  const isLoading = false; // Placeholder for loading state

  const fetchContacts = () => {
    console.log('Fetch contacts functionality will be implemented here.');
    // Future Alloy contact fetch code will be added here
  };

  // Component UI remains the same
}

Enter fullscreen mode Exit fullscreen mode

And here’s the updated code for ContactList.js with Alloy integration:

// components/ContactList.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import styles from './css/ContactList.module.css';

export default function ContactList({ connectionId }) {
  const [contacts, setContacts] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  const fetchContacts = async () => {
    if (connectionId) {
      setIsLoading(true);
      try {
        const response = await axios.get(`/api/contacts?connectionId=${connectionId}`);
        setContacts(response.data.contacts);
        setIsLoading(false);
      } catch (error) {
        console.error('Error fetching contacts:', error);
        setIsLoading(false);
      }
    }
  };

  // Rest of the component remains the same
}

Enter fullscreen mode Exit fullscreen mode

1. Configure CreateContact.js:

Adapt CreateContact.js in the src/app/components directory to utilize your contacts.js API route for creating new contacts.

The initial code template looks like this:

import React, { useState } from 'react';
import styles from './css/CreateContact.module.css';

export default function CreateContact({ connectionId }) {
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');

  const handleSubmit = (event) => {
    event.preventDefault();
    console.log('Create contact functionality will be implemented here.', { firstName, lastName });
    // Future Alloy contact creation code will be added here
  };

  // Component UI remains the same
}

Enter fullscreen mode Exit fullscreen mode

The completed code looks like this:

// components/CreateContact.js
import React, { useState } from 'react';
import axios from 'axios';
import styles from './css/CreateContact.module.css';

export default function CreateContact({ connectionId }) {
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');

  const handleSubmit = async (event) => {
    event.preventDefault();
    if (connectionId) {
      try {
        const response = await axios.post(`/api/contacts?connectionId=${connectionId}`, { firstName, lastName });
        console.log('Contact added:', response.data);
        setFirstName('');
        setLastName('');
      } catch (error) {
        console.error('Error adding contact:', error);
      }
    } else {
      console.error('No connection ID. Please connect to Salesforce first.');
    }
  };

  // Rest of the component remains the same

}

Enter fullscreen mode Exit fullscreen mode

Instructions:

  • In ContactList.js, the fetchContacts function is implemented to fetch contacts using Axios.
  • In CreateContact.js, the handleSubmit function is updated to create a new contact and interact with the API.
  • Ensure that the connection ID is checked before making API calls.

Wrapping up

By completing this tutorial, you have built a CRM integration using Next.js and Alloy, gaining experience in connecting to Salesforce, managing contacts, and integrating front-end and back-end in a Next.js application.

As a reminder, you can sign up for a live, guided version of this tutorial here !

Top comments (2)

Collapse
 
fpires profile image
Felipe Pires

Crazy how powerful Alloy seems to be!

Collapse
 
johnboxcodes profile image
joaquim

wow, this saves a lot of pain !