Developing a Salesforce integration, quickly & easily
Tags: javascript, react, tutorial, api
Published: 2024-01-09 20:54:38

_This post was originally published at [runalloy.com](https://runalloy.com/blog/developing-a-salesforce-integration/)._

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)](https://app.runalloy.com/signup)

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](https://github.com/alloy-automation/salesforce-crm-demo) 

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](https://www.producthunt.com/products/alloy-automation).

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](https://www.linkedin.com/events/zerotointegrated-buildanativesa7148756965702213632/comments/)!

## 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
```

**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'
```

**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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6918blcouppn4v8ga42a.png)

## 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' });
  }
}

```

**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>
  );
}
```
**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.' });
}

```
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`);
  }
}

```
**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
}

```
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
}

```

**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
}

```
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
 
}

```
**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](https://www.linkedin.com/events/zerotointegrated-buildanativesa7148756965702213632/comments/) !