Create a serverless API with Next.js and Mailchimp
Tags: nextjs, react, node, serverless
Published: 2020-05-13 17:11:32

EDIT: Now updated with environment variables and fetch!

---

The future is API-driven. We have APIs for [weather](https://openweathermap.org/api), [payments](https://stripe.com/docs/api), [travel](https://www.partners.skyscanner.net/affiliates/travel-apis), and even [sports](http://www.espn.com/apis/devcenter/io-docs.html?ref=public-apis). [RESTful](https://restfulapi.net) architecture and API frameworks are what make ordinary apps and websites into powerful tools in today's connected world.

Using these frameworks, we can create tailored experiences for users, without having to reinvent the systems that power those experiences. In this tutorial, we will use Next.js, a fantastic React-based web development framework, 

This tutorial assumes you are familiar with React, Next.js, and RESTful architecture. 

## Initial Setup
Setting up Next.js is super simple:
```shell
npm init next-app
```

Next.js will set up a default project and install all dependencies for you. Once installed, inside of the `pages/` directory, you will find the default Next.js `index.js` welcome page. If you start the development server and make changes to this file, you will see the changes updated live in your browser.

## Create the API
In this tutorial, we’ll be using Mailchimp’s API to add a new email address as a contact in a campaign mailing list.

To create an API, create a folder named `api/` in the `pages/` directory. Next.js will take any file inside the `api/` folder and create an API instead of a page. Here, create a new file named `subscribe.js`. This API will be accessible from the web at `your-site.com/api/subscribe`.

Next.js provides a clean framework to handle the request and response in the API. All we need to do here is take the email address from the request and send it to Mailchimp’s API. Let’s start by exporting a default function in `subscribe.js` that returns a JSON object with one key-value pair:
```jsx
export default async (req, res) => {
  res.end(JSON.stringify({response: 'hello world'}))
}
```
The `async` keyword is important, as we will be using the companion `await` keyword to make asynchronous calls to Mailchimp.

You can visit the API endpoint in the browser or using a tool like Postman and see the response we coded in the last step.
```json
{
  "response": "hello world"
}
```

In Next.js, `req` and `res` are default parameters sent and expected by the framework. `req` is an object that contains all of the request data — headers, cookies, query values, and of course, the request body. We should only need the body at this point, accessible via the `req.body` object. Let's expect a field called `emailAddress` in the request, which will contain the new email address for the new subscriber. We'll pull that into a variable called `email` for later.
```jsx
export default async (req, res) => {
  const email = req.body.emailAddress
}
```

To call Mailchimp's API that will add an email address to your mailing list, first [create an API](https://mailchimp.com/help/about-api-keys/) within your Mailchimp account. Using this key, you will authenticate your requests to Mailchimp, similar to a password. This will be stored and executed from the our `subscribe` API, so no visitor to your website will ever see it.

To call APIs, we will need to use an HTTP client like `fetch`, which comes bundled with Next.js.

The `fetch` API is simple to use. We just need to call `fetch()` with Mailchimp’s URL and an object containing the required parameters. Since `fetch()` returns a [Promise](https://developers.google.com/web/fundamentals/primers/promises), we will use `await` to resolve it. Since both the Promise and the fetch call could fail, we wrap the call in a `try-catch` block.
```jsx
try {
  const response = await fetch({
    // parameters will go here
  })
} catch { }
```

The [Mailchimp API documentation](https://mailchimp.com/developer/reference/lists/list-members/#post_/lists/-list_id-/members) defines the endpoint and calls for two fields to be sent in the request: the `email_address`, for which we will pass the `email` value extracted from `req.body` earlier, and the `status` for that email address, for which we will send `subscribed`. The [fetch documentation](https://www.npmjs.com/package/axios) shows that the first parameter in the `fetch()` call is the URL, and the second parameter is an object with additional fields. The `body` field is where we will pass the `email_address` and `status` fields. We need to use `JSON.stringify()` to convert the fields into a single string.

Mailchimp’s endpoint is a `POST` call, so let’s set the `method` to that, and additionally define a `headers` object so we can pass  `Content-Type`, which will be `application/json`.
```jsx
const email = req.body.emailAddress
try {
    const response = await fetch('https://{dc}.api.mailchimp.com/3.0/lists/{listId}/members', {
      method: 'post',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': secret,
      },
      body: JSON.stringify({
        email_address: email,
        status: 'subscribed'
      })
    })
} catch { }
```

*NOTE: To create the complete URL for your Mailchimp mailing list, you will need to find the `dc` location and `list_id` for your account in Mailchimp's dashboard.*

One last step is to add the `Authorization` field to the header. This will authenticate our request with Mailchimp's server with [HTTP Basic Authentication](https://mailchimp.com/developer/guides/get-started-with-mailchimp-api-3/#Authentication_methods) using the API key created earlier.  An easy way to create the Authorization token is using [Postman's authorization tool](https://learning.postman.com/docs/postman/sending-api-requests/authorization/#basic-auth). You can also create it manually by encoding your Mailchimp username and API key in `Base64`.

The authorization token needs to be passed in the `headers` object, but we should avoid keeping sensitive data like tokens, keys, and passwords unencrypted as strings in a file. Instead, let’s create an environment variable that will be encrypted and stored securely outside of our code. Our app will find and use it automatically.

Create a `.env` file in the root of the project. This will store a list of environment variables as key-value pairs. The key can be anything, and the value will be the `Base64` encoded token for Mailchimp. Remember to wrap the value in quotes.
```
MAILCHIMP_SECRET="Basic s0m3L0ngR@ndomStr1nG"
```

Don’t forget to ignore this file in your source control — we don’t want to be syncing this plaintext file. It is best to recreate this file wherever your code will run. This file will help run your code on your local machine, and you can set up environment variables on most cloud platforms.

Once the token is saved, we can pull it from the `env` object and send it in our `fetch` request:
```jsx
const { MAILCHIMP_AUTH: secret } = process.env
// { ... }
try {
    const response = await fetch('https://{dc}.api.mailchimp.com/3.0/lists/{listId}/members', {
      method: 'post',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': secret,
      },
      body: JSON.stringify({
        email_address: email,
        status: 'subscribed'
      })
    })
} catch { }
```

Now we just need to return the correct response from our API depending on the `response` we get from Mailchimp. We will only send back a response status, and leave the response body empty since there is no data to be communicated back to the browser. To keep things simple in this tutorial, if Mailchimp returns a `200` response status, we will also return a `200`. If Mailchimp returns anything else, we will return a `400` status. It either subscribed the user, or it didn't.
```jsx
// const response = { ... }
if (response.status === 200) {
  res.statusCode = 200
  res.end()
} else {
  res.statusCode = 400
  res.end()
}
```

Now, `fetch` will throw an error if the call fails. This could be due to a network issue or a legitimate error returned from the Mailchimp API. This error will be caught in the `catch` block, so let's make sure it returns a response too.
```jsx
// try { ...
} catch (error) {
  res.statusCode = 400
  res.end()
}
```

And that's it! We have an API that will call Mailchimp with an email address and return a status code depending on Mailchimp's response. If you run the development server, you can test this in Postman by sending an email address in the body of a `POST` request. In response, we will either get a `200` code or `400` code, just as we coded for.
```json
{
    "emailAddress" : "user@example.com"
}
```

In the next part of this tutorial, we will set up some validation and security in our API before deploying to the web, and we will also set up the frontend component — that is, the form itself.