mailchimp教程_如何将MailChimp集成到JavaScript Web应用程序中

mailchimp教程

by Timur (Tima) Zhiyentayev

通过帖木儿(蒂玛)日因耶捷

如何将MailChimp集成到JavaScript Web应用程序中 (How to integrate MailChimp in a JavaScript web app)

If you are a blogger, publisher, or business owner who does content marketing, having a newsletter is a must. In this tutorial, you will learn how to add Mailchimp integration to a simple JavaScript app. You’ll ultimately build a form for guest users to subscribe to a newsletter.

如果您是从事内容营销的博客作者,发布者或企业所有者,则必须拥有时事通讯。 在本教程中,您将学习如何将Mailchimp集成添加到一个简单JavaScript应用程序。 您最终将建立一个供访客用户订阅新闻通讯的表单。

I wrote this tutorial for a junior/mid-career web developer. The tutorial assumes some basic knowledge of React, JavaScript, and HTTP.

我为初级/中级Web开发人员编写了本教程。 本教程假定您具有React,JavaScript和HTTP的一些基本知识

You’ll start the tutorial with a boilerplate app, gradually add code to it, and finally test Mailchimp API integration.

您将以样板应用程序开始本教程,逐步向其中添加代码,最后测试Mailchimp API集成。

The boilerplate app is built with React, Material-UI, Next, Express, Mongoose, and MongoDB. Here’s more about the boilerplate.

样板应用程序使用React,Material-UI,Next,Express,Mongoose和MongoDB构建。 这是有关样板的更多信息。

As mentioned above, our goal is to create a feature that allows a guest user to subscribe to a MailChimp newsletter. The user subscribes by manually adding their email address to a form on your website. Here is an overview of the data exchange that will occur between the client (browser) and server:

如上所述,我们的目标是创建一个允许来宾用户订阅MailChimp新闻通讯的功能。 用户通过手动将其电子邮件地址添加到您网站上的表单进行订阅。 这是客户端(浏览器)和服务器之间将进行的数据交换的概述:

  • A user adds their email address to the form and clicks submit

    用户将其电子邮件地址添加到表单中,然后单击“ submit

  • The click triggers a client-side API method that sends the email address from the user’s browser to your app server

    单击将触发客户端API方法,该方法将从用户的浏览器将电子邮件地址发送到您的应用服务器
  • The client-side API method sends a POST request to a unique Express route

    客户端API方法将POST请求发送到唯一的Express路由
  • The Express route passes the email address to a server-side API method that sends a POST request to Mailchimp’s server

    Express路由将电子邮件地址传递到服务器端API方法,该方法将POST请求发送到Mailchimp的服务器
  • The email address is successfully added to your Mailchimp list

    电子邮件地址已成功添加到您的Mailchimp列表中

Specifically, you will achieve the following by the end of this tutorial:

具体来说,您将在本教程结束时实现以下目标:

  • Create a Subscribe page with a subscription form

    使用订阅表单创建Subscribe页面

  • Define an API method called subscribeToNewsletter() using the fetch()method

    使用fetch()方法定义一个称为subscribeToNewsletter()的API方法

  • Define an Express route '/subscribe'

    定义快递路线'/subscribe'

  • Define a subscribe() API method that sends a POST request to Mailchimp's API server

    定义一个subscription subscribe() API方法,该方法将POST请求发送到Mailchimp的API服务器

  • Test out this data exchange with Postman and as a guest user

    与Postman和来宾用户一起测试此数据交换

入门 (Getting started)

For this tutorial, we’ll use code located in the 1-start folder of our builderbook repo. If you don’t have time to run the app locally, I deployed this example app at: https://mailchimp.builderbook.org/subscribe

在本教程中,我们将使用位于builderbook repo1-start文件夹中的代码 。 如果您没有时间在本地运行该应用程序, 在以下位置部署此示例应用程序: https : //mailchimp.builderbook.org/subscribe

To run the app locally:

要在本地运行该应用程序:

  • Clone the builderbook repo to your local machine with:

    使用以下命令将builderbook存储库克隆到本地计算机:
git clone git@github.com:builderbook/builderbook.git
  • Inside the 1-start folder, run yarn or npm install to install all packages listed in package.json.

    1-start文件夹中,运行yarnnpm install安装package.json列出的所有软件包。

To add Mailchimp API to our app, we will install and learn about the following packages:

要将Mailchimp API添加到我们的应用程序,我们将安装并了解以下软件包:

Let’s start by putting together the Subscribe page. In addition to learning about the Mailchimp API, you will get familiar with Next.js, a framework for React apps.

让我们从整理“ Subscribe页面开始。 除了学习Mailchimp API之外,您还将熟悉React应用程序框架Next.js。

A key feature of Next.js is server-side rendering for initial page load. Other features include routing, prefetching, hot code reload, code splitting, and preconfigured webpack.

Next.js的关键功能是用于初始页面加载的服务器端呈现。 其他功能包括路由,预取,热代码重载,代码拆分和预配置的Webpack。

订阅页面 (Subscribe page)

We will define a Subscribe component as a child of ES6 class using extends.

我们将使用extendsSubscribe组件定义为ES6类的子

Instead of:

代替:

const Subscribe = React.createClass({})

We will use:

我们将使用:

class Subscribe extends React.Component {}

We will not specify ReactDOM.render() or ReactDOM.hydrate explicitly, since Next.js implements both internally.

我们不会明确指定ReactDOM.render()ReactDOM.hydrate ,因为Next.js在内部实现了两者。

A high-level structure for our Subscribe page component is:

我们的“ 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;

Create a subscribe.js file inside the pages folder of 1-start. Add the above code to this file. We will fill the // other imports section as we go.

1-startpages文件夹内创建一个subscribe.js文件。 将上面的代码添加到此文件。 我们将继续// other imports部分。

Our form will have only two elements: (1) an input element for email addresses and (2) a button. Since our boilerplate app is integrated with Material-UI, we’ll use TextField and Button components from the Material-UI library. Add these two imports to your subscribe.js file:

我们的表单只有两个元素:(1)电子邮件地址的输入元素和(2)按钮。 由于样板应用程序已与Material-UI集成在一起,因此我们将使用Material-UI库中的TextFieldButton组件。 将这两个导入添加到您的subscribe.js文件中:

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

Put the TextField and Button components inside a <form> element:

TextFieldButton组件放在<fo rm>元素内:

<form onSubmit={this.onSubmit}>  <p>We will email you when a new tutorial is released:</p>  <TextField    type="email"    label="Your email"    style={styleTextField}    required  />  <p />  <Button variant="raised" color="primary" type="submit"&gt;    Subscribe  </Button></form>

You can see that we passed some props to both TextField and Button components. For a complete list of props you can pass, check out the official docs for TextField props and Button props.

您可以看到我们将一些道具传递给了TextFieldButton组件。 有关可以通过的道具的完整列表,请查看TextField道具Button道具的官方文档。

We need to get an email address specified in TextField. To access the value of TextField, we add React's ref attribute to it:

我们需要获取在TextField指定的电子邮件地址。 要访问TextField的值,我们向其添加React的ref属性

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

We access the value with:

我们通过以下方式访问值:

this.emailInput.value

Two notes:

两个注意事项:

  • We did not use ref="emailInput", since React documentation recommends using the contextual object this. In JavaScript, this is used to access an object in the context. If you configure Eslint properly, you would see an Eslint warning for this rule.

    我们没有使用ref="emailInput" ,因为React文档建议使用上下文对象this 。 在JavaScript中, this用于访问上下文中的对象。 如果您正确配置了Eslint,则会看到此规则的Eslint警告。

  • Instead of ref, we used inputRef since the TextField component is not an input HTML element. TextField is a component of Material-UI and uses the inputRef prop instead of ref.

    因为TextField组件不是input HTML元素,所以我们使用了inputRef而不是refTextField是Material-UI的组件,并使用inputRef代替ref

Before we define our onSubmit function, let's run our app and take a look at our form. Your code at this point should look like: pages/subscribe.js

在定义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 (      <div style={{ padding: '10px 45px' }}>        <Head>          <title>Subscribe</title>          <meta name="description" content="description for indexing bots" />        </Head>        <br />        <form onSubmit={this.onSubmit}>          <p>We will email you when a new tutorial is released:</p>          <TextField            inputRef={(elm) => {              this.emailInput = elm;            }}            type="email"            label="Your email"            style={styleTextField}            required          />          <p />          <Button variant="raised" color="primary" type="submit">            Subscribe          </Button>        </form>      </div>    );  }}
export default withLayout(Subscribe);

A few notes:

一些注意事项:

  • In Next.js, you can specify page title and description using Head. See how we used it above.

    在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.

    我们添加了一个styleTextField样式。 我们将这种样式保留在components/SharedStyles.js ,以便可重用并且可以将其导入任何组件或页面中。

  • 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.

    我们用withLayout包装了Subscribe组件。 withLayout的高阶组件可确保页面获取Header组件,并在初始加载时在服务器端呈现。

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.

我们通过/subscribe路由访问Subscribe页面,因为Next.js从pages文件夹内的pages文件名创建页面的路由。

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

yarn dev启动您的应用程序,然后转到http://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:

该窗体看起来像预期的那样。 尝试更改传递给TextFieldButton组件的不同属性的值。 例如,将label prop的文本更改为Type your email ,并将Button variant prop更改为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.

在继续之前,请单击“ Header的“ Log in链接。 请注意页面顶部的加载进度栏。 我们使用Nprogress实现了该栏,并在等待代码将电子邮件地址发送到Mailchimp列表时显示它。

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.

下一步是定义onSubmit函数。 此功能的目的是从TextField获取电子邮件地址,将该电子邮件地址传递给API方法subscribeToNewsletter ,然后调用该方法。

Before we call subscribeToNewsletter(email), let's prevent a default behavior of our <form> element and define email:

在调用subscribeToNewsletter(email) ,让我们防止<fo rm>元素和d efine电子邮件的默认行为:

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:

    让我们定义一个本地变量email 。 它具有价值this.emailInput.value如果两个this.emailInputthis.emailInput.value存在,否则是无效:

const email = (this.emailInput && this.emailInput.value) || null;
  • If email is null, the function should return undefined:

    如果email为null,则函数应返回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.

要调用我们的API方法subscribeToNewsletter(email) ,让我们将async/await构造与try/catch一起使用。 我们在本书中详细介绍了异步回调, Promise.thenasync/await

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

要使用async/await ,请在async添加一个匿名箭头函数,如下所示:

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):

提供subscribeToNewsletter(email)应该返回一个Promise(并且确实如此—我们在本教程后面的部分中使用JavaScript的fetch()方法定义了此方法,该方法返回一个Promise)。 您可以预先await subscriptionToNewsletter 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.

JavaScript将在行上暂停并await subscribeToNewsletter({ email }); 并且仅在subscribeToNewsletter({ email })返回带有成功或错误消息的响应后才继续。

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:

在定义我们的subscribeToNewsletter API方法之前,让我们进行UX改进。 使用NProgress.start(); 开始加载酒吧并使用NProgress.done(); 完成条形加载:

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

您的“ Subscribe页面的代码应类似于: 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 (      <div style={{ padding: '10px 45px' }}>        <Head>          <title>Subscribe</title>          <meta name="description" content="description for indexing bots" />        </Head>        <br />        <form onSubmit={this.onSubmit}>          <p>We will email you when a new tutorial is released:</p>          <TextField            inputRef={(elm) => {              this.emailInput = elm;            }}            type="email"            label="Your email"            style={styleTextField}            required          />          <p />          <Button variant="raised" color="primary" type="submit">            Subscribe          </Button>        </form>      </div>    );  }}
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().

yarn dev启动您的应用程序,并确保您的页面和表单看起来符合预期。 由于尚未定义API方法subscribeToNewsletter() ,因此无法提交表单。

subscriptionToNewsletter API方法 (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.

正如您可能在pages/subscribe.js的import部分中注意到的那样,我们将在lib/api/public.js定义lib/api/public.js subscribeToNewsletter() 。 我们将subscribeToNewsletter()放置在lib文件夹中,以使其可以普遍访问,这意味着此API方法将在客户端(浏览器)和服务器上均可用。 我们这样做是因为在Next.js中,页面代码是在初始加载时在服务器端呈现的,而在后续加载时是客户端呈现的。

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.

在我们的情况下,当用户单击浏览器上的按钮以调用subscribeToNewsletter() ,此方法将仅在客户端上运行。 但是,假设您有一个getPostList API方法可获取博客文章列表。 要在服务器上呈现包含帖子列表的页面必须使getPostList普遍可用。

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.

回到我们的API方法subscribeToNewsletter() 。 正如我们在本教程的简介中讨论的那样,我们的目标是建立客户端与服务器之间的数据交换。 换句话说,我们的目标是为我们的应用程序构建内部API。 这就是为什么我们将subscribeToNewsletter()称为API方法。

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.

subscribeToNewsletter()的目的是通过称为API端点的特定路由向服务器发送请求 ,然后接收响应。 我们在这里详细讨论HTTP和请求/响应。

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).

要理解本教程,您应该知道,使用POST方法发送了将数据传递到服务器且不需要返回任何数据的请求。 通常,请求的body包含数据(在我们的示例中为电子邮件地址)。

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

除了发送请求之外,我们的subscribeToNewsletter()方法还应等待响应。 响应不必包含任何数据-它可以是带有一个参数{ subscribed: 1 }{ done: 1 }{ 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.

为了实现发送请求和接收响应的双重目的,我们使用了fetch()方法。 在JavaScript中, fetch()是一种全局方法,用于通过发送请求和接收响应来通过网络获取数据。

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

我们使用isomorphic-fetch包,该包使fetch()在我们的Node环境中可用。 使用以下命令安装此软件包:

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:

让我们使用此示例编写一个可重用的sendRequest方法, sendRequest方法采用path和其他一些options ,传递一个请求对象(具有methodcredentialsoptions属性的对象),然后调用fetch()方法。 fetch()path和请求对象作为参数:

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).

isomorphic-fetch的示例不同,我们使用了我们最喜欢的async/await构造而不是Promise.then (以提高代码的可读性)。

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.

Object.assign()是一种从三个较​​小的对象中创建新对象{ method: 'POST', credentials: 'include' }{ headers }options 。 默认情况下,对象options为空,但可以是例如请求的body属性。 由于我们需要传递电子邮件地址,因此我们的案例确实使用了body属性。

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:

正如您可能从代码中注意到的那样,我们需要定义ROOT_URL 。 我们可以为ROOT_URL编写条件逻辑,该条件逻辑考虑了NODE_ENVPORT ,但是为了简单起见,我们将其定义为:

const ROOT_URL = 'http://localhost:8000';

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

是时候借助sendRequest方法来定义我们的subscribeToNewsletter方法了:

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.

如您所见,我们传递{ body: JSON.stringify({ email }), }作为options对象,以将电子邮件地址添加到请求对象的主体中。

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.

另外,我们选择/api/v1/public/subscribe作为我们的path ,这是内部API的API端点,该API将用户电子邮件地址添加到Mailchimp列表中。

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

放在一起, lib/api/public.js应为: lib/api/public.js

import 'isomorphic-fetch';
const ROOT_URL = 'http://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.

做好这一点! 我们定义了subscribeToNewsletter API方法,该方法将请求发送到API端点/api/v1/public/subscribe并接收响应。

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:

使用yarn dev启动您的应用程序,添加电子邮件地址,然后提交表单。 在浏览器控制台中( Developer tools > Cons控制台),您将看到预期的ed POST 404错误:

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.

该错误意味着请求已成功发送到服务器,但是服务器未找到请求的内容。 这是预期的行为,因为当请求发送到相应的API端点时,我们没有编写任何服务器代码来将响应发送给客户端。 换句话说,我们没有创建处理通过使用subscribeToNewsletter API方法发送的POST请求的Express路由/api/v1/public/subscribe

快速路线/订阅 (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.

Express路由指定当API方法从客户端向路由的API端点发送请求时执行的功能。 在我们的例子中,当我们的API方法将请求发送到API端点/api/v1/public/subscribe ,我们希望服务器使用执行某些功能的Express路由来处理此请求。

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

您可以使用express.Router()类和router.METHOD()语法根据用户类型将Express路由模块化为小组:

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().

如果您想了解更多信息,请查看express.Router()router.METHOD()上的官方Express文档。

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.

并将以上代码直接放入我们的主服务器代码中,位于server/app.js

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

您已经有足够的信息来整理基本的Express路线:

  • The method is POST

    方法是POST
  • The API endpoint is /api/v1/public/subscribe

    API端点为/api/v1/public/subscribe

  • From writing onSubmit and subscribeToNewsletter, you know about an anonymous arrow function

    通过编写onSubmitsubscribeToNewsletter ,您将了解匿名箭头功能

  • From writing onSubmit, you know about the try/catch construct

    通过编写onSubmit ,您可以了解try/catch构造

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({ error: err.message || 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.

    我们写了error: err.message || err.toString() error: err.message || err.toString()处理以下两种情况:当错误是字符串类型时,以及错误是对象时。

  • To test out our Express route, we added the line:

    为了测试我们的Express路线,我们添加了以下行:
console.log(‘non-error response is sent’);

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

在此行之后,将上述Express路由添加到server/app.js

const server = express();

It’s time to test!

现在该进行测试了!

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

我们建议您使用Postman应用程序来测试请求-响应周期。

Look at this snapshot of request properties in Postman:

查看Postman中请求属性的快照:

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

您需要至少指定三个属性(类似于我们编写subscribeToNewsletter API方法时的属性):

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

确保您的应用正在运行。 从yarn dev开始。 现在单击邮递员上的Send按钮。

If successful, you will see the following two outputs:

如果成功,您将看到以下两个输出:

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

    在Postman上,您看到响应的代码为200和以下正文:

2. Your terminal prints:

2.您的终端打印:

Good job, you just wrote a working Express route!

做得好,您刚刚写了一条有效的Express路线!

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:

至此,您证明了两个事件在您的应用程序中成功发生:发送请求并接收到响应。 但是,我们没有将电子邮件地址传递给Express路由内的函数。 为此,我们需要访问req.body.email ,因为这是我们在定义subscribeToNewsletter API方法时保存电子邮件地址的位置:

const email = req.body.email;

With ES6 object destructuring, it becomes shorter:

通过ES6对象分解,它变得更短:

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):

如果email局部变量不存在,那么我们发送一个带有错误的响应并返回undefined(以空白return退出):

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

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

另外,修改console.log语句以打印出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({ error: err.message || err.toString() });  }});

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

让我们测试一下。 打开邮差,还有一个属性添加到我们的要求: body与价值team@builderbook.org 。 确保选择raw > J SON数据格式:

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

确保您的应用程序正在运行,然后单击“ Send按钮。

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

查看有关Postman的响应和终端的输出:

  1. Postman will display Loading... but never finish

    邮递员将显示“ Loading...但永远不会完成

  2. Terminal outputs an error: TypeError: Cannot read property 'email' of undefined

    终端输出错误: 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.

显然, email变量未定义。 要从req.body读取email属性,您需要一个实用程序,该实用程序将请求的body对象从Unicode解码为JSON格式。 该实用程序称为bodyParser在此处了解更多信息

Install bodyParser:

安装bodyParser

yarn add body-parser

Import it to server/app.js with:

使用以下命令将其导入到server/app.js

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:

在服务器上安装JSON bodyParser 。 在const server = express();之后添加以下行 您的Express路线之前

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:

使用外部bodyParser包的替代方法是使用内部Express中间件express.json() 。 为此,请删除bodyParser的导入代码, bodyParser以上代码行替换为:

server.use(express.json());

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

我们准备测试。 确保您的应用程序正在运行,然后单击Postman上的“ Send按钮。

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

看一下Postman和您的终端上的响应:

  1. Postman successfully outputs: "subscribed": 1

    邮递员成功输出: "subscribed": 1

  2. Terminal has no error this time, instead it prints: team@builderbook.org

    终端这次没有错误,而是打印: team@builderbook.org

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

太好了,现在请求的body已解码,并且在Express路由的功能内可以作为req.body

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

您已成功向该应用添加了第一个内部API! 客户端和服务器之间的数据交换按预期进行。

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.

快递航线,我们之前写的里面,我们要打电话,等待subscribe发送从我们的服务器Mailchimp的POST请求方法。 在本教程的下一个也是最后一部分,我们将讨论并编写subscribe方法。

方法subscription() (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.

我们编写了代码,以实现服务器与用户浏览器之间的正确数据交换。 但是,要将用户的电子邮件地址添加到Mailchimp列表中,我们需要将服务器发送到服务器 POST请求。 从我们的服务器Mailchimp的服务器的 POST请求。

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

要将服务器发送到服务器请求,我们将使用request包。 安装它:

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):

与任何请求一样,我们需要弄清楚要包含的API端点和请求属性( headersbody等):

  • Create a server/mailchimp.js file.

    创建一个server/mailchimp.js文件。

  • Import request.

    导入request

  • Define request.post() (POST request) with these properties: uri, headers, json, body, and callback.

    使用以下属性定义request.post() (POST请求): uriheadersjsonbody和callback。

server/mailchimp.js :

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:

所有属性都是不言自明的,但是我们应该讨论uri (或API端点)和Authorization标头:

1. uri. Earlier in this chapter, we picked http://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:

1. uri 。 在本章的前面,我们选择了http://localhost:8000/api/v1/public/subscribe作为我们的API端点。 我们可以为内部API选择任何路线。 但是,Mailchimp的API是外部的。 因此,我们应该检查官方文档以找到将电子邮件地址添加到列表的API端点。 阅读有关API的更多信息, 以将成员添加到列表中 。 API端点是:

https://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:

区域usX是一个子域。 请按照以下步骤查找API端点的子域:

  • sign up or log in to Mailchimp

    注册或登录Mailchimp
  • go to Account > Extras > API keys > Your API keys

    转到Account > Extras > API keys > Your API密钥

  • your API key may look like xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us17

    您的API密钥可能类似于xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us17

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

这表示该地区为us17 ,您的应用程序会将请求发送到Mailchimp子域:

https://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:

变量LIST_ID是Mailchimp帐户中特定列表的列表ID。 要查找List ID ,请按照下列步骤操作:

  • On your Mailchimp dashboard, go to Lists > click the list name > Settings > List name and defaults

    在Mailchimp仪表板上,转到Lists > click the list name > Settings > List name and默认值

  • Find the section List ID

    找到“ List ID ”部分

  • Get the xxxxxxxxxx value from this section, it's your LIST_ID

    从此部分获取xxxxxxxxxx值,这是您的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:

2. Authorization头。 我们需要将Authorization标头中的API_KEY发送到Mailchimp的服务器。 这告诉Mailchimp的服务器我们的应用程序有权发送请求。 在此处阅读有关授权标头的更多信息( headers.Authorization )。 Authorization标头的语法:

Authorization:
  • In our case:

    在我们的情况下:
Authorization: Basic apikey:API_KEY

The API_KEY must be base64 encoded. Follow this example.

API_KEY必须是base64编码的。 请遵循此示例

After encoding:

编码后:

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

To find API_KEY:

要找到API_KEY

  • On your Mailchimp dashboard, go to Account > Extras > API keys > Your API keys

    在Mailchimp仪表板上,转到Account > Extras > API keys > Your API密钥

  • Your API key may look like xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us17

    您的API密钥可能类似于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:

我们将在哪里存储listIdAPI_KEY值? 您可以将所有环境变量存储在.env文件中,并使用dotenv软件包进行管理。 但是,为了专注于本教程,我们将值直接添加到我们的server/mailchimp.js文件中:

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: `https://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.

记住要为listIdAPI_KEY添加实际值。

测试中 (Testing)

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

现在该测试整个MailChimp订阅流程了。

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:

我们出口我们的subscribe从方法server/mailchimp.js ,但我们并没有进口/添加在此方法快速通道server/app.js 。 为此:

  • Import to server/app.js with:

    使用以下命令导入到server/app.js

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:

    向Express路由添加async/await构造,因此我们调用并等待 subscribe方法。 修改如下代码片段:

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 || err.toString() });  }});

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().

我们能够使用await进行subscribe因为此方法返回了Promise。 回想定义subscribe -它有一个符合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:

让我们从pages/subscribe.jsonSubmit函数添加console.log语句。 打开pages/subscribe.js文件,并添加console.log如下所示:

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.

此时,我们可以跳过对Postman的测试。 相反,让我们启动应用程序,填写表格,提交表格,然后检查电子邮件是否已添加到Mailchimp列表中。 另外,我们将看到浏览器控制台的输出。

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

yarn dev启动您的应用程序。 转到http://localhost:8000/subscribe 。 查看Mailchimp仪表板上的空白列表:

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

填写表格,然后单击“ Subscribe 。 用Mailchimp列表刷新页面:

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: https://mailchimp.builderbook.org/subscribe. You’ll get a test email to confirm that MailChimp API worked.

如果您不在本地运行该应用程序,则可以在我为本教程部署的应用程序上进行测试: https : //mailchimp.builderbook.org/subscribe 。 您会收到一封测试电子邮件,以确认MailChimp API是否有效。

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

繁荣! 您刚刚学习了两项强大的技能:为JavaScript Web应用程序构建内部和外部API。

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.

完成本教程后,您的代码应与1端文件夹中的代码匹配。 该文件夹位于我们的builderbook repotutorials目录中。

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.

如果您认为这篇文章很有用,请考虑给我们的Github回购加星号,并查看我们的 ,其中详细介绍了此主题和许多其他主题。

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).

如果您要开发软件产品,请查看我们的SaaS样板Async (面向小型软件工程师团队的团队沟通理念和工具)。

翻译自: https://www.freecodecamp.org/news/how-to-integrate-mailchimp-in-a-javascript-web-app-2a889fb43f6f/

mailchimp教程

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值