كيفية دمج MailChimp في تطبيق ويب JavaScript

إذا كنت مدونًا أو ناشرًا أو صاحب عمل يقوم بتسويق المحتوى ، فإن وجود رسالة إخبارية أمر لا بد منه. في هذا البرنامج التعليمي ، ستتعلم كيفية إضافة تكامل Mailchimp إلى تطبيق JavaScript بسيط. ستقوم في النهاية بإنشاء نموذج للمستخدمين الضيوف للاشتراك في رسالة إخبارية.

لقد كتبت هذا البرنامج التعليمي لمطور ويب مبتدئ / متوسط ​​العمر. يفترض البرنامج التعليمي بعض المعرفة الأساسية بـ React و JavaScript و HTTP .

ستبدأ البرنامج التعليمي باستخدام تطبيق معياري ، ثم تضيف رمزًا تدريجيًا إليه ، وأخيراً تختبر تكامل Mailchimp API.

تم إنشاء تطبيق boilerplate باستخدام React و Material-UI و Next و Express و Mongoose و MongoDB. إليك المزيد حول النموذج المعياري.

كما ذكرنا أعلاه ، فإن هدفنا هو إنشاء ميزة تسمح للمستخدم الضيف بالاشتراك في رسالة إخبارية من MailChimp. يشترك المستخدم عن طريق إضافة عنوان بريده الإلكتروني يدويًا إلى نموذج على موقع الويب الخاص بك. فيما يلي نظرة عامة على تبادل البيانات الذي سيحدث بين العميل (المتصفح) والخادم:

  • يضيف المستخدم عنوان بريده الإلكتروني إلى النموذج وينقر submit
  • تؤدي النقرة إلى تشغيل طريقة واجهة برمجة تطبيقات من جانب العميل ترسل عنوان البريد الإلكتروني من متصفح المستخدم إلى خادم التطبيق الخاص بك
  • ترسل طريقة API من جانب العميل طلب POST إلى مسار Express فريد
  • يمرر المسار السريع عنوان البريد الإلكتروني إلى طريقة API من جانب الخادم والتي ترسل طلب POST إلى خادم Mailchimp
  • تمت إضافة عنوان البريد الإلكتروني بنجاح إلى قائمة Mailchimp الخاصة بك

على وجه التحديد ، ستحقق ما يلي بنهاية هذا البرنامج التعليمي:

  • إنشاء Subscribeصفحة مع نموذج الاشتراك
  • حدد طريقة API تسمى subscribeToNewsletter()باستخدام fetch()الطريقة
  • تحديد طريق سريع '/subscribe'
  • حدد subscribe()طريقة API التي ترسل طلب POST إلى خادم واجهة برمجة تطبيقات Mailchimp
  • اختبر تبادل البيانات هذا مع ساعي البريد وكمستخدم ضيف

ابدء

في هذا البرنامج التعليمي ، سنستخدم الكود الموجود في المجلد 1-start الخاص بنا من builderbook repo. إذا لم يكن لديك الوقت لتشغيل التطبيق محليًا ، فقد قمت بنشر هذا المثال التطبيق على: //mailchimp.builderbook.org/subscribe

لتشغيل التطبيق محليًا:

  • قم باستنساخ builderbook repo إلى جهازك المحلي باستخدام:
git clone [email protected]:builderbook/builderbook.git
  • داخل 1-startالمجلد ، قم بتشغيل yarnأو npm installتثبيت جميع الحزم المدرجة في package.json.

لإضافة Mailchimp API إلى تطبيقنا ، سنقوم بتثبيت الحزم التالية والتعرف عليها:

  • متماثل الشكل
  • محلل الجسم
  • طلب

لنبدأ بتجميع Subscribeالصفحة. بالإضافة إلى التعرف على واجهة برمجة تطبيقات Mailchimp ، ستتعرف على Next.js ، وهو إطار عمل لتطبيقات React.

الميزة الرئيسية لـ Next.js هي العرض من جانب الخادم للتحميل الأولي للصفحة. تشمل الميزات الأخرى التوجيه ، والجلب المسبق ، وإعادة تحميل الكود السريع ، وتقسيم الكود ، وحزمة الويب المكونة مسبقًا.

صفحة الاشتراك

سنقوم بتعريف Subscribeالمكون على أنه تابع لفئة ES6 باستخدام الامتدادات.

بدلا من:

const Subscribe = React.createClass({})

سوف نستخدم:

class Subscribe extends React.Component {}

لن نحدد ReactDOM.render()أو ReactDOM.hydrateصراحة ، لأن Next.js ينفذ كلاهما داخليًا.

هيكل عالي المستوى Subscribeلمكون الصفحة الخاص بنا هو:

import React from 'react';// other imports
class Subscribe extends React.Component { onSubmit = (e) => { // check if email is missing, return undefined // if email exists, call subscribeToNewsletter() API method };
render() { return ( // form with input and button ); }}
export default Subscribe;

قم بإنشاء subscribe.jsملف داخل pagesمجلد 1-start. أضف الكود أعلاه إلى هذا الملف. سنملأ // other importsالقسم كما نمضي.

سيحتوي النموذج الخاص بنا على عنصرين فقط: (1) عنصر إدخال لعناوين البريد الإلكتروني و (2) زر. نظرًا لأن تطبيقنا المعياري متكامل مع Material-UI ، فسنستخدم مكونات TextField و Button من مكتبة Material-UI. أضف هذين الواردين إلى ملفك subscribe.js:

import TextField from 'material-ui/TextField';import Button from 'material-ui/Button';

وضع TextFieldو Buttonمكونات داخل rm> element:

We will email you when a new tutorial is released:

يمكنك أن ترى أن تجاوزنا بعض الدعائم لكلا TextFieldو Buttonالمكونات. للحصول على قائمة كاملة بالدعامات التي يمكنك تمريرها ، تحقق من المستندات الرسمية للدعائم TextField و Button.

نحتاج إلى الحصول على عنوان بريد إلكتروني محدد في TextField. للوصول إلى قيمة TextField، نضيف إليها سمة ref الخاصة بـ React:

inputRef={(elm) => { this.emailInput = elm;}}

نصل إلى القيمة من خلال:

this.emailInput.value

ملاحظتان:

  • لم نستخدم ref="emailInput"، لأن وثائق React توصي باستخدام الكائن السياقي this. في JavaScript ، thisيستخدم للوصول إلى كائن في السياق. إذا قمت بتكوين Eslint بشكل صحيح ، فسترى تحذير Eslint لهذه القاعدة.
  • بدلاً من ذلك ref، استخدمنا inputRefلأن TextFieldالمكون ليس inputعنصر HTML. TextFieldهو أحد مكونات Material-UI ويستخدم inputRefالخاصية بدلاً من ref.

قبل أن نحدد onSubmitوظيفتنا ، دعنا نشغل تطبيقنا ونلقي نظرة على النموذج الخاص بنا. يجب أن يبدو الرمز الخاص بك في هذه المرحلة كما يلي:pages/subscribe.js

import React from 'react';import Head from 'next/head';import TextField from 'material-ui/TextField';import Button from 'material-ui/Button';
import { styleTextField } from '../components/SharedStyles';import withLayout from '../lib/withLayout';
class Subscribe extends React.Component { onSubmit = (e) => { // some code };
render() { return ( Subscribe

We will email you when a new tutorial is released:

{ this.emailInput = elm; }} type="email" label="Your email" style={styleTextField} required />

Subscribe ); }}
export default withLayout(Subscribe);

بعض الملاحظات:

  • في Next.js ، يمكنك تحديد عنوان الصفحة ووصفها باستخدام Head. انظر كيف استخدمناها أعلاه.
  • We added a styleTextField style. We keep this style in components/SharedStyles.js, so that it's reusable and can be imported into any component or page.
  • We wrapped the Subscribe component with withLayout. The higher-order component withLayout ensures that a page gets a Header component and is server-side rendered on initial load.

We access the Subscribe page at the /subscribe route, since Next.js creates the route for a page from the page's file name inside the pages folder.

Start your app with yarn dev and go to //localhost:8000/subscribe

The form looks as expected. Try changing the values passed to different props of the TextField and Button components. For example, change text for the label prop to Type your email and change the Button variant prop to flat:

Before we continue, click the Log in link in the Header. Note the loading progress bar at the top of the page. We implemented this bar with Nprogress, and we will show it while waiting for our code to send an email address to a Mailchimp list.

Our next step is to define the onSubmit function. The purpose of this function is to get the email address from TextField, pass that email address to an API method subscribeToNewsletter, and then call the method.

Before we call subscribeToNewsletter(email), let's prevent a default behavior of our rm> element and d efine email:

  • Prevent the default behavior of sending form data to a server with:
e.preventDefault();
  • Let’s define a local variable email . It has the value this.emailInput.value if both this.emailInput and this.emailInput.value exist, otherwise it is null:
const email = (this.emailInput && this.emailInput.value) || null;
  • If email is null, the function should return undefined:
if (this.emailInput && !email) { return;}

So far we have:

onSubmit = (e) => { e.preventDefault();
const email = (this.emailInput && this.emailInput.value) || null;
if (this.emailInput && !email) { return; }
// call subscribeToNewsletter(email)};

To call our API method subscribeToNewsletter(email), let's use the async/await construct together with try/catch. We cover async callbacks, Promise.then, and async/await in detail in our book.

To use async/await, prepend async to an anonymous arrow function like this:

onSubmit = async (e) =>

Providing subscribeToNewsletter(email) should return a Promise (and it does — we define this method later in this tutorial using JavaScript's fetch()method that returns a Promise). You can prepend await to subscribeToNewsletter(email):

await subscribeToNewsletter({ email })

You get:

onSubmit = async (e) => { e.preventDefault();
const email = (this.emailInput && this.emailInput.value) || null;
if (this.emailInput && !email) { return; }
try { await subscribeToNewsletter({ email });
if (this.emailInput) { this.emailInput.value = ''; } } catch (err) { console.log(err); //eslint-disable-line }};

JavaScript will pause at the line with await subscribeToNewsletter({ email }); and continue only after subscribeToNewsletter({ email }) returns a response with a success or error message.

In the case of success, let’s clear our form with:

if (this.emailInput) { this.emailInput.value = ''; }

Before we define our subscribeToNewsletter API method, let's make a UX improvement. Use NProgress.start(); to start bar loading and use NProgress.done(); to complete bar loading:

onSubmit = async (e) => { e.preventDefault();
const email = (this.emailInput && this.emailInput.value) || null;
if (this.emailInput && !email) { return; }
NProgress.start();
try { await subscribeToNewsletter({ email });
if (this.emailInput) { this.emailInput.value = ''; }
NProgress.done(); } catch (err) { console.log(err); //eslint-disable-line NProgress.done(); }};

With this change, a user who submits a form will see the progress bar.

Code for your Subscribe page should look like: pages/subscribe.js

import React from 'react';import Head from 'next/head';import TextField from 'material-ui/TextField';import Button from 'material-ui/Button';import NProgress from 'nprogress';
import { styleTextField } from '../components/SharedStyles';import withLayout from '../lib/withLayout';import { subscribeToNewsletter } from '../lib/api/public';
class Subscribe extends React.Component { onSubmit = async (e) => { e.preventDefault();
const email = (this.emailInput && this.emailInput.value) || null;
if (this.emailInput && !email) { return; }
NProgress.start();
try { await subscribeToNewsletter({ email });
if (this.emailInput) { this.emailInput.value = ''; }
NProgress.done(); console.log('non-error response is received'); } catch (err) { console.log(err); //eslint-disable-line NProgress.done(); } };
render() { return ( Subscribe

We will email you when a new tutorial is released:

{ this.emailInput = elm; }} type="email" label="Your email" style={styleTextField} required />

Subscribe ); }}
export default withLayout(Subscribe);

Start your app with yarn dev and make sure your page and form look as expected. Submitting a form won't work yet, since we haven't defined the API method subscribeToNewsletter().

subscribeToNewsletter API method

As you may have noticed from the import section of pages/subscribe.js, we will define subscribeToNewsletter() at lib/api/public.js. We placed subscribeToNewsletter() to the lib folder to make it universally accessible, meaning this API method will be available on both client (browser) and server. We do so because in Next.js, page code is server-side rendered on initial load and client-side rendered on subsequent loads.

In our case, when a user clicks a button on the browser to call subscribeToNewsletter() , this method will run only on the client. But imagine that you have a getPostList API method that fetches a list of blog posts. To render a page with a list of posts on the server, you have to make getPostList universally available.

Back to our API method subscribeToNewsletter(). As we discussed in the introduction to this tutorial, our goal is to hook up a data exchange between client and server. In other words, our goal is to build an internal API for our app. That's why we call subscribeToNewsletter() an API method.

The purpose of subscribeToNewsletter() is to send a request to the server at a particular route called an API endpoint and then receive a response. We discuss HTTP and request/response in detail here.

To understand this tutorial, you should know that a request that passes data to the server and does not require any data back is sent with the POST method. Usually, the request's body contains data (in our case, email address).

In addition to sending a request, our subscribeToNewsletter() method should wait for a response. The response does not have to contain any data — it could be a simple object with one parameter { subscribed: 1 } or { done: 1 } or { success: 1 }.

To achieve both sending a request and receiving a response, we use the fetch() method. In JavaScript, fetch() is a global method that is used for fetching data over a network by sending a request and receiving a response.

We use the isomorphic-fetch package that makes fetch() available in our Node environment. Install this package with:

yarn add isomorphic-fetch

Here’s an example of usage from the package’s README:

fetch('//offline-news-api.herokuapp.com/stories') .then(function(response) { if (response.status >= 400) { throw new Error("Bad response from server"); } return response.json(); }) .then(function(stories) { console.log(stories); });

Let’s use this example to write a reusable sendRequest method that takes path and some other options, passes a request object (object that has method, credentials and options properties), and calls the fetch()method. fetch() takes path and the request object as arguments:

async function sendRequest(path, options = {}) { const headers = { 'Content-type': 'application/json; charset=UTF-8', };
const response = await fetch( `${ROOT_URL}${path}`, Object.assign({ method: 'POST', credentials: 'include' }, { headers }, options), );
const data = await response.json();
if (data.error) { throw new Error(data.error); }
return data;}

Unlike the example from isomorphic-fetch, we used our favorite async/await construct instead of Promise.then (for better code readability).

Object.assign() is a method that creates a new object out of three smaller objects: { method: 'POST', credentials: 'include' }, { headers }, and options. The object options is empty by default, but it could be, for example, the request's body property. Since we need to pass an email address, our case indeed uses the body property.

As you may have noticed from the code, we need to define ROOT_URL. We can write conditional logic for ROOT_URL that takes into consideration NODE_ENV and PORT, but for simplicity’s sake, we define it as:

const ROOT_URL = '//localhost:8000';

It’s time to define our subscribeToNewsletter method with the help of the sendRequest method:

export const subscribeToNewsletter = ({ email }) => sendRequest('/api/v1/public/subscribe', { body: JSON.stringify({ email }), });

As you can see, we pass { body: JSON.stringify({ email }), } as an options object to add an email address to the body of the request object.

Also we chose /api/v1/public/subscribe as our path, that is the API endpoint for our internal API that adds a user email address to our Mailchimp list.

Put it all together and the content of the lib/api/public.js should be: lib/api/public.js

import 'isomorphic-fetch';
const ROOT_URL = '//localhost:8000';
async function sendRequest(path, options = {}) { const headers = { 'Content-type': 'application/json; charset=UTF-8', };
const response = await fetch( `${ROOT_URL}${path}`, Object.assign({ method: 'POST', credentials: 'include' }, { headers }, options), );
const data = await response.json();
if (data.error) { throw new Error(data.error); }
return data;}
export const subscribeToNewsletter = ({ email }) => sendRequest('/api/v1/public/subscribe', { body: JSON.stringify({ email }), });

Good job reaching this point! We defined our subscribeToNewsletter API method that sends a request to the API endpoint /api/v1/public/subscribe and receives a response.

Start your app with yarn dev, add an email address, and submit the form. In your browser console (Developer tools > Console), you will see an expected POST 404 error:

That error means that the request was successfully sent to the server, but the server did not find what was requested. This is expected behavior since we did not write any server code that sends a response to the client when a request is sent to corresponding API endpoint. In other words, we did not create the Express route /api/v1/public/subscribe that handles the POST request we sent using the subscribeToNewsletter API method.

Express route/subscribe

An Express route specifies a function that gets executed when an API method sends a request from the client to the route’s API endpoint. In our case, when our API method sends a request to the API endpoint /api/v1/public/subscribe, we want the server to handle this request with an Express route that executes some function.

You can use the class express.Router() and syntax router.METHOD()to modularize Express routes into small groups based on user type:

const router = express.Router();router.METHOD('API endpoint', ...);

If you’d like to learn more, check out the official Express docs on express.Router() and router.METHOD().

However, in this tutorial, instead of modularizing, we will use:

server.METHOD('API endpoint', ...);

And place the above code directly into our main server code at server/app.js.

You already have enough information to put together a basic Express route:

  • The method is POST
  • The API endpoint is /api/v1/public/subscribe
  • From writing onSubmit and subscribeToNewsletter, you know about an anonymous arrow function
  • From writing onSubmit, you know about the try/catch construct

Put all this knowledge together, and you get:

server.post('/api/v1/public/subscribe', (req, res) => { try { res.json({ subscribed: 1 }); console.log('non-error response is sent'); } catch (err) { res.json( err.toString() ); }});

A couple of notes:

  • We wrote error: err.message || err.toString() to handle both situations: when the error is a type of string and when the error is an object.
  • To test out our Express route, we added the line:
console.log(‘non-error response is sent’);

Add the above Express route to server/app.js after this line:

const server = express();

It’s time to test!

We recommend using the Postman app for testing out a request-response cycle.

Look at this snapshot of request properties in Postman:

You need to specify at least three properties (similar to when we wrote the subscribeToNewsletter API method):

  • Select POST method
  • Specify the full path for the API endpoint: //localhost:8000/api/v1/public/subscribe
  • Add a Content-Type header with the value application/json

Make sure your app is running. Start it with yarn dev. Now click the Send button on Postman.

If successful, you will see the following two outputs:

  1. On Postman, you see the response has code 200 and the following body:

2. Your terminal prints:

Good job, you just wrote a working Express route!

At this point, you showed that two events happen successfully in your app: a request gets sent and a response is received. However, we did not pass an email address to a function inside our Express route. To do so, we need to access req.body.email, because this is where we saved the email address when defining the subscribeToNewsletter API method:

const email = req.body.email;

With ES6 object destructuring, it becomes shorter:

const { email } = req.body;

If the email local variable does not exist, then let's send a response with an error and return undefined (exit with blank return):

if (!email) { res.json({ error: 'Email is required' }); return;}

Also, modify the console.log statement to print out email.

After these modifications, you get:

server.post('/api/v1/public/subscribe', async (req, res) => { const { email } = req.body;
if (!email) { res.json({ error: 'Email is required' }); return; }
try { res.json({ subscribed: 1 }); console.log(email); } catch (err) { res.json( err.toString() ); }});

Let’s test it out. Open Postman, and add one more property to our request: body with value [email protected]. Make sure that you selected the raw > JSON data format:

Make sure that your app is running and then click the Send button.

Look at the response on Postman and the output of your terminal:

  1. Postman will display Loading... but never finish
  2. Terminal outputs an error: TypeError: Cannot read property 'email' of undefined

Apparently, the email variable is undefined. To read the email property from req.body, you need a utility that decodes the body object of a request from Unicode to JSON format. This utility is called bodyParser, read more about it here.

Install bodyParser:

yarn add body-parser

Import it to server/app.js with:

import bodyParser from 'body-parser';

Mount JSON bodyParser on the server. Add the following line right after const server = express(); and before your Express route:

server.use(bodyParser.json());

An alternative to using the external bodyParser package is to use internal Express middleware express.json(). To do so, remove the import code for bodyParser and replace the above line of code with:

server.use(express.json());

We are ready to test. Make sure your app is running and click the Send button on Postman.

Take a look at the response on Postman and your terminal:

  1. Postman successfully outputs: "subscribed": 1
  2. Terminal has no error this time, instead it prints: [email protected]

Great, now the request’s body is decoded and available inside the Express route's function as req.body.

You successfully added the first internal API to this app! Data exchange between client and server works as expected.

Inside the Express route that we wrote earlier, we want to call and wait for a subscribe method that sends a POST request from our server to Mailchimp's. In the next and final section of this tutorial, we will discuss and write the subscribe method.

Method subscribe()

We wrote code for proper data exchange between our server and a user’s browser. However, to add a user’s email address to a Mailchimp list, we need to send a server to server POST request. POST request from our server to Mailchimp’s server.

To send a server to server request, we will use the request package. Install it:

yarn add request

As with any request, we need to figure out which API endpoint and what request properties to include (headers, body and so on):

  • Create a server/mailchimp.js file.
  • Import request.
  • Define request.post() (POST request) with these properties: uri, headers, json, body, and callback.

server/mailchimp.js :

import request from 'request';
export async function subscribe({ email }) { const data = { email_address: email, status: 'subscribed', };
await new Promise((resolve, reject) => { request.post( { uri: // to be discussed headers: { Accept: 'application/json', Authorization: // to be discussed, }, json: true, body: data, }, (err, response, body) => { if (err) { reject(err); } else { resolve(body); } }, ); });}

All properties are self-explanatory, but we should discuss uri (or API endpoint) and Authorization header:

1. uri. Earlier in this chapter, we picked //localhost:8000/api/v1/public/subscribe as our API endpoint. We could've picked any route for our internal API. However, Mailchimp’s API is external. Thus we should check the official documentation to find the API endpoint that adds an email address to a list. Read more about the API to add members to a list. The API endpoint is:

//usX.api.mailchimp.com/3.0/lists/{LIST_ID}/members

Region usX is a subdomain. Follow these steps to find the subdomain for an API endpoint:

  • sign up or log in to Mailchimp
  • go to Account > Extras > API keys > Your API keys
  • your API key may look like xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us17

That means the region is us17 and your app will send requests to the Mailchimp subdomain:

//us17.api.mailchimp.com/3.0/lists/{LIST_ID}/members

Variable LIST_ID is the List ID of a particular list in your Mailchimp account. To find List ID, follow these steps:

  • On your Mailchimp dashboard, go to Lists > click the list name > Settings > List name and defaults
  • Find the section List ID
  • Get the xxxxxxxxxx value from this section, it's your LIST_ID

2. Authorization header. We need to send our API_KEY inside Authorizationheader to Mailchimp's server. This tells Mailchimp's server that our app is authorized to send a request. Read more about Authorization header here (headers.Authorization). Syntax for Authorization header:

Authorization:
  • In our case:
Authorization: Basic apikey:API_KEY

The API_KEY must be base64 encoded. Follow this example.

After encoding:

Authorization: `Basic ${Buffer.from(`apikey:${API_KEY}`).toString(‘base64’)}`

To find API_KEY:

  • On your Mailchimp dashboard, go to Account > Extras > API keys > Your API keys
  • Your API key may look like xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us17

Where are we going to store listId and API_KEY values? You can store all environmental variable in a .env file and manage them with the dotenv package. However, to stay focused in this tutorial, we add values directly to our server/mailchimp.js file:

const listId = 'xxxxxxxxxx';const API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us17';

Plug in the above code snippets:

import request from 'request';
export async function subscribe({ email }) { const data = { email_address: email, status: 'subscribed', };
const listId = 'xxxxxxxxxx'; const API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us17';
await new Promise((resolve, reject) => { request.post( { uri: `//us17.api.mailchimp.com/3.0/lists/${listId}/members/`, headers: { Accept: 'application/json', Authorization: `Basic ${Buffer.from(`apikey:${API_KEY}`).toString('base64')}`, }, json: true, body: data, }, (err, response, body) => { if (err) { reject(err); } else { resolve(body); } }, ); });}

Remember to add real values for listId and API_KEY.

Testing

It’s time to test out the entire MailChimp subscription flow.

We exported our subscribe method from server/mailchimp.js, but we haven't imported/added this method to the Express route at server/app.js. To do so:

  • Import to server/app.js with:
import { subscribe } from ‘./mailchimp’;
  • Add an async/await construct to the Express route, so we call and wait for the subscribe method. Modify the following snippet of code like this:
server.post('/api/v1/public/subscribe', async (req, res) => { const { email } = req.body; if (!email) { res.json({ error: 'Email is required' }); return; }
 try { await subscribe({ email }); res.json({ subscribed: 1 }); console.log(email); } catch (err) { res.json( error: err.message ); }});

We were able to use await for subscribe because this method returns a Promise. Recall the definition of subscribe — it has a line with new Promise().

Let’s add a console.log statement to the onSubmit function from pages/subscribe.js. Open your pages/subscribe.js file and add console.log like this:

try { await subscribeToNewsletter({ email });
if (this.emailInput) { this.emailInput.value = ''; } NProgress.done(); console.log('email was successfully added to Mailchimp list');} catch (err) { console.log(err); //eslint-disable-line NProgress.done();}

At this point, we can skip testing with Postman. Instead, let’s start our app, fill out the form, submit the form, and check if the email was added to the Mailchimp list. Also, we will see the output of our browser console.

Start your app with yarn dev. Go to //localhost:8000/subscribe. Take a look at the empty list on your Mailchimp dashboard:

Fill out the form and click Subscribe. Refresh the page with the Mailchimp list:

And the browser console prints:

In case you are not running the app locally, you can test on the app I deployed for this tutorial: //mailchimp.builderbook.org/subscribe. You’ll get a test email to confirm that MailChimp API worked.

Boom! You just learned two powerful skills: building internal and external APIs for your JavaScript web application.

When you complete this tutorial, your code should match code in the 1-end folder. This folder is located in the tutorials directory of our builderbook repo.

If you found this article useful, consider giving a star to our Github repo and checking out our book where we cover this and many other topics in detail.

If you are building a software product, check out our SaaS boilerplate and Async (team communication philosophy and tool for small teams of software engineers).