---
title: Back4App와 Stripe 통합 가이드: 클라우드 코드 활용하기
slug: docs-kr/cloud-code-functions/integrations/stripe
description: Back4App 클라우드 코드로 Stripe 결제 시스템을 통합하는 방법 알아보기.
image: https://www.back4app.com/images/logo-social.png
createdAt: 2024-02-28T14:23:44.608Z
---

# 클라우드 기능을 사용한 스트라이프 통합

## 소개

이 가이드에서는 Back4App에서 호스팅된 백엔드를 스트라이프 API와 통합하는 방법을 보여줍니다. Back4App에서 이를 구축하기 위한 최상의 아키텍처 선택은 [클라우드 기능](https://www.back4app.com/docs/get-started/cloud-functions). 스트라이프와의 클라우드 기능 통합을 완료하면 모든 프론트엔드 프로젝트(웹, iOS, 안드로이드)에서 이 통합을 사용할 수 있습니다. 이 가이드는 웹 예제를 사용한 완전한 스트라이프 통합을 제공합니다.

## 전제 조건

:::hint{type="info"}
이 튜토리얼을 완료하려면 다음이 필요합니다:




- Back4App에서 생성된 앱.
- &#x20;[새 앱 만들기 튜토리얼](https://www.back4app.com/docs/get-started/new-parse-app)을 따라 Back4App에서 앱을 만드는 방법을 배우십시오.
- &#x20;[스트라이프](https://stripe.com/br)에 계정이 생성되어야 합니다.
:::

## 목표

Back4App 클라우드 기능을 사용하여 웹 프로젝트에 스트라이프 통합.

## 스트라이프란 무엇인가?

[스트라이프](https://stripe.com/)는 25개국 이상에서 운영되는 기술 회사로, 개인과 기업이 인터넷을 통해 결제를 받을 수 있도록 합니다. 스트라이프는 온라인 결제 시스템을 운영하는 데 필요한 기술, 사기 방지 및 은행 인프라를 제공하는 데 중점을 둡니다.

이 튜토리얼에서는 웹 앱에 Parse Server에 Stripe API를 통합하고 기능을 생성하는 단계를 안내합니다.

보다 구체적으로, 이 가이드에서는 사용자가 로그인하거나 가입하고, 신용 카드를 등록하고, Stripe Payments를 통해 예제 구매를 생성할 수 있는 환경을 만들 것입니다. 또한 서버와 Stripe API의 연결이 제대로 작동하는지 테스트하는 방법도 안내합니다.

## 1 - Stripe 계정 만들기

Stripe에 가서 [계정 만들기](https://dashboard.stripe.com/register)를 클릭하세요. 거기서 개인 정보를 제공하고 계정이 속한 국가를 선택하기만 하면 됩니다.

다음으로, Stripe 계정을 확인하세요(Stripe에서 확인 링크가 포함된 이메일을 받게 됩니다). 해당 링크를 클릭한 후, Stripe 이메일 주소를 확인하는 단계를 따르세요.

## 2 - 데이터베이스 클래스 설정

1단계에서 Stripe 환경을 구성한 후, 데이터베이스를 설정할 수 있도록 Back4App 앱 대시보드로 이동하세요. 이 단계는 필수는 아니지만, Parse가 클라우드 함수가 새 객체를 생성하려고 할 때 자동으로 클래스를 생성하므로, 어떤 필드가 생성될지와 그 이유를 설명하기 위해 진행하겠습니다.

앱의 Stripe 관련 데이터를 보유할 두 개의 클래스가 있습니다: <font color="#2166ae">`PaymentMethod`</font> 및 <font color="#2166ae">`Payment`</font>:

클래스가 배치되는 방식은 다음과 같습니다:

- <font color="#2166ae">`PaymentMethod`</font>
  - <font color="#2166ae">`type`</font>(String): 값은 항상 “card”입니다;
  - <font color="#2166ae">`card`</font>(Object): 등록된 카드에 대한 전체 Stripe 데이터를 보유합니다;
  - <font color="#2166ae">`stripeID`</font>(String): Stripe 백엔드에서 이 PaymentMethod를 참조하는 ID입니다;
  - <font color="#2166ae">`user`</font>(Pointer to Parse.User): 이 PaymentMethod가 속한 User에 대한 직접 참조입니다.
- <font color="#2166ae">`Payment`</font>
  - <font color="#2166ae">`data`</font>(Object): 결제에 대한 전체 Stripe 데이터를 보유합니다;
  - <font color="#2166ae">`user`</font>(Pointer to Parse.User): 이 Payment가 속한 User에 대한 직접 참조입니다.

또한 앱 기본 <font color="#2166ae">`String`</font> 값 열을 두 개 추가할 것입니다. <font color="#2166ae">`User`</font> 클래스에 <font color="#2166ae">`setupSecret`</font> 및 <font color="#2166ae">`customerId`</font>가 포함되어 Stripe ID를 포함하여 <font color="#2166ae">`User`</font>를 Stripe 상대방과 연결합니다.

## 3 - 클라우드 코드 구현

앱에서 [클라우드 코드 함수](https://docs.parseplatform.org/cloudcode/guide/#cloud-functions)를 구성하고, Stripe 모듈을 설치한 후 코드를 배포합시다.

:::hint{type="info"}
**클라우드 코드 환경을 더 잘 이해하고 싶다면, [이 가이드](https://www.back4app.com/docs/get-started/cloud-functions).**&#x20;
:::

### 3.1 - Stripe 키 가져오기

이제 Stripe 대시보드를 열고, 상단의 <font color="#2166ae">`개발자`</font> 페이지로 이동한 후 왼쪽 메뉴에서 <font color="#2166ae">`API 키`</font>를 선택하세요. 해당 섹션에서 <font color="#2166ae">`발행 가능 키`</font>와 <font color="#2166ae">`비밀 키`</font>를 확인할 수 있습니다.

![](https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/XdeM4pK8gQagvIiLc0vd6_image.png)

이 키들을 적어두세요. 나중에 필요할 것입니다.

### 3.2 - 클라우드 코드 파일

컴퓨터에서 다음 파일을 생성하세요. 이 파일들은 모듈을 설치하고 Cloud Code 기능을 Back4App에 추가하는 역할을 합니다.

```json
1   {
2     "dependencies": {
3       "stripe": "*"
4     }
5   }
```

아래 코드를 새 파일에 추가하고 Stripe 비밀 키를 맨 위에 붙여넣는 것을 잊지 마세요.

:::CodeblockTabs
main.js

```javascript
1   const STRIPE_SECRET_KEY =
2     "YOUR_STRIPE_SECRET_KEY";
3   const stripe = require("stripe")(STRIPE_SECRET_KEY);
4
5   // Stripe needs an unique customer id to create payments, so after
6   // signing up, this function should be called to do this operation
7   Parse.Cloud.define("createStripeCustomer", async (request) => {
8     // Get Parse.User object
9     const userQuery = new Parse.Query(Parse.User);
10    userQuery.equalTo("objectId", request.params.userId);
11    let user = await userQuery.first();
12  
13    const customer = await stripe.customers.create({ email: user.get("email") });
14    // Creates an stripe setupIntent, that will enable the stripe lib to perform
15    // a singel operation related to payments
16    const intent = await stripe.setupIntents.create({
17      customer: customer.id,
18    });
19    // Set and save the stripe ids to the Parse.User object
20    user.set({
21      customerId: customer.id,
22      setupSecret: intent.client_secret,
23    });
24    return await user.save(null, { useMasterKey: true });
25  });
26
27  // Creates new payment method for a registered customer
28  Parse.Cloud.define("addNewPaymentMethod", async (request) => {
29    // Get Parse.User object
30    const userQuery = new Parse.Query(Parse.User);
31    userQuery.equalTo("objectId", request.params.userId);
32    let user = await userQuery.first();
33
34    // Retrieve complete stripe payment method by its id
35    const stripePaymentMethod = await stripe.paymentMethods.retrieve(
36      request.params.paymentMethodId
37    );
38
39    // Create a new SetupIntent so the customer can add a new method next time.
40      const intent = await stripe.setupIntents.create({
41      customer: `${stripePaymentMethod.customer}`,
42    });
43    user.set("setupSecret", intent.client_secret);
44    user = await user.save(null, { useMasterKey: true });
45
46    // Creates a new Parse object in the PaymentMethod class
47    let PaymentMethod = new Parse.Object("PaymentMethod");
48    PaymentMethod.set({
49      user: user,
50      type: "card",
51      stripeId: stripePaymentMethod.id,
52      card: stripePaymentMethod.card,
53    });
54    PaymentMethod.save();
55    return true;
56  });
57
58  // Creates a new payment using a valid payment method
59  Parse.Cloud.define("createNewPayment", async (request) => {
60    // Get Parse.User object
61    const userQuery = new Parse.Query(Parse.User);
62    userQuery.equalTo("objectId", request.params.userId);
63    let user = await userQuery.first();
64
65    const { amount, currency, payment_method } = request.params.paymentData;
66
67    // Look up the Stripe customer id.
68    const customer = user.get("customerId");
69
70    // Create a charge using an unique idempotency key
71    // to protect against double charges.
72    const idempotencyKey = new Date().getTime();
73    const payment = await stripe.paymentIntents.create(
74      {
75        amount,
76        currency,
77        customer,
78        payment_method,
79        off_session: false,
80        confirm: true,
81        confirmation_method: "manual",
82      },
83      { idempotencyKey }
84    );
85    // If the result is successful, write it back to the database.
86    let Payment = new Parse.Object("Payment");
87    Payment.set({
88      user: user,
89      data: payment,
90    });
91    await Payment.save();
92
93    return true;
94  });

```
:::

## 4 - 클라우드 코드에 함수 업로드

Back4App 웹사이트로 이동하여 로그인한 후 앱을 찾으세요. 그 후 <font color="#2166ae">`대시보드`</font> 링크를 클릭하면 아래에 표시된 페이지로 이동합니다. Cloud Code를 배포하려면 <font color="#2166ae">`+ 추가`</font> 버튼을 클릭하고 이전 단계에서 생성한 <font color="#2166ae">`main.js`</font> 및 <font color="#2166ae">`package.json`</font> 파일을 찾은 후 <font color="#2166ae">`배포`</font> 버튼을 클릭하세요.

![](https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/6TdryEG35btnknL02_lCa_image.png)

:::hint{type="info"}
방금 모든 플랫폼에서 사용할 수 있는 Cloud Code 기능을 구성했습니다! [함수 배포 및 호출](https://www.back4app.com/docs/get-started/cloud-functions) 가이드를 확인하여 호출하는 방법을 배우세요. 다음 단계에서는 이들을 호출하는 JavaScript 프로젝트를 작업할 것입니다.
:::

## 5 - Cloud Code와 JavaScript 앱 통합

이제 Parse에서 사용자를 로그인하거나 가입시키고, 유효한 결제 방법(신용 카드)을 생성하고, 사용자의 결제 방법으로 새로운 결제를 생성하는 세 가지 주요 기능이 있는 간단한 HTML 페이지의 예를 볼 수 있습니다.

계속해서 컴퓨터에 새 디렉토리와 다음 코드를 포함한 새 HTML 파일을 생성하세요:

:::CodeblockTabs
index.html

```html
1   <!DOCTYPE html>
2   <html lang="en">
3
4   <head>
5       <meta charset="UTF-8" />
6       <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7       <title>Back4App Stripe Payments</title>
8       <link rel="stylesheet" href="app.css">
9   </head>
10
11  <body>
12      <header class="header">
13          <img class="header_logo"
14              src="https://blog.back4app.com/wp-content/uploads/2019/05/back4app-white-logo-500px.png" alt="">
15          <p class="header_text_bold">React on Back4App</p>
16          <p class="header_text">Back4App Stripe Payments</p>
17      </header>
18      <section id="auth">
19          <div class="container">
20              <div class="form_wrapper">
21                  <form id="auth-signin-form">
22                      <h2 class="form_heading">Sign In</h2>
23                      <input class="form_input" type="email" name="email" placeholder="Email" required />
24                      <input class="form_input" type="password" name="password" placeholder="Password" required />
25                      <button class="form_button" type="submit">
26                          Sign in
27                      </button>
28                      <a class="form_hint" id="signup-toggle" href="#">Don't have an account yet? Sign up instead.</a>
29                  </form>
30                  <form id="auth-signup-form" hidden>
31                      <h2 class="form_heading">Sign Up</h2>
32                      <input class="form_input" type="email" name="email" placeholder="Email" required />
33                      <input class="form_input" type="password" name="password" placeholder="Password" required />
34                      <button class="form_button" type="submit">
35                          Sign up
36                      </button>
37                      <a class="form_hint" id="signin-toggle" href="#">Already have an account? Sign in instead.</a>
38                  </form>
39              </div>
40          </div>
41      </section>
42      <section id="content" style="display: none;">
43          <div class="container">
44              <div>
45                  <h2 class="form_heading">Add new payment method</h2>
46                  <p>
47                      Use any of the
48                      <a href="https://stripe.com/docs/testing#international-cards" target="_blank">Stripe test cards</a>
49                      for this demo!
50                  </p>
51                  <form class="form" id="payment-method-form">
52                      <input class="form_input" type="text" name="name" placeholder="Cardholder name" required />
53                      <div class="card_element_wrapper">
54                          <div id="card-element"></div>
55                      </div>
56                      <button class="form_button">Save Card</button>
57                  </form>
58              </div>
59              <div>
60                  <h2 class="form_heading">Create new payment</h2>
61                  <form class="form" id="payment-form">
62                      <select class="form_input" name="payment-method" required>
63                          <option disabled selected>Card (payment method):</option>
64                      </select>
65                      <div>
66                          <input class="form_input" name="amount" type="number" min="1" max="99999999"
67                              placeholder="Amount" required />
68                          <select class="form_input" name="currency">
69                              <option disabled selected>Currency:</option>
70                              <option value="usd">USD</option>
71                              <option value="brl">BRL</option>
72                              <option value="eur">EUR</option>
73                          </select>
74                      </div>
75                      <button class="form_button">Charge selected card</button>
76                  </form>
77              </div>
78              <div class="form">
79                  <h2 class="form_heading">Payments</h2>
80                  <ul id="payments-list"></ul>
81              </div>
82              <button type="button" id="signout">
83                  Sign out
84              </button>
85          </div>
86      </section>
87      <script type="text/javascript" src="https://npmcdn.com/parse/dist/parse.min.js"></script>
88      <script type="text/javascript" src="https://js.stripe.com/v3/"></script>
89      <script type="text/javascript" src="index.js"></script>
90  </body>
91
92  </html>
```
:::

이 파일에는 두 개의 주요 섹션이 있습니다. 첫 번째는 인증 섹션으로, 사용자가 아직 로그인하지 않은 경우 기본적으로 렌더링됩니다. 로그인 후에는 결제 섹션이 표시되며, 여기에는 Stripe에서 데이터를 생성하고 Back4App의 Cloud Code 함수와 통신하는 모든 양식이 포함됩니다.

이제 모든 것을 연결하는 코드를 포함하는 JavaScript 함수를 만들어야 합니다. 그 함수의 이름은 <font color="#2166ae">`index.js`</font>:

:::CodeblockTabs
index.js

```javascript
1   // Define and initialize Parse and Stripe libs
2   const PARSE_APP_ID = "YOUR_PARSE_ID";
3   const PARSE_JS_KEY = "YOUR_PARSE_JS_KEY";
4   Parse.initialize(PARSE_APP_ID, PARSE_JS_KEY);
5   Parse.serverURL = "https://parseapi.back4app.com/";
6
7   const STRIPE_PUBLISHABLE_KEY = "YOUR_STRIPE_PUBLISHABLE_KEY";
8   const stripe = Stripe(STRIPE_PUBLISHABLE_KEY);
9
10  // Holds the currentUser complete Parse object
11  let currentUser = null;
12  const setCompleteCurrentUser = async () => {
13    // Called when user is already signed in, completing
14    // the currentUser object with the full one
15    currentUser = await new Parse.Query(Parse.User)
16      .equalTo("objectId", Parse.User.current().id)
17      .first();
18    // Retrieve and render user cards and payments
19    retrieveCurrentUserPaymentMethods();
20    retrieveCurrentUserPayments();
21  };
22
23  const retrieveCurrentUserPaymentMethods = async () => {
24    // Query and render user PaymentMethods
25    const PMQuery = new Parse.Query("PaymentMethod");
26    PMQuery.equalTo("user", Parse.User.current());
27    paymentMethods = await PMQuery.find();
28    renderPaymentMethodOptions(paymentMethods);
29  };
30
31  const retrieveCurrentUserPayments = async () => {
32    // Query and render user Payments
33    const paymentsQuery = new Parse.Query("Payment");
34    paymentsQuery.equalTo("user", Parse.User.current());
35    payments = await paymentsQuery.find();
36    renderPayments(payments);
37  };
38  
39  const renderPaymentMethodOptions = async (paymentMethods) => {
40    for (let paymentMethod of paymentMethods) {
41      const optionId = `card-${paymentMethod.get("stripeId")}`;
42      let optionElement = document.getElementById(optionId);
43  
44      // Add a new option if one doesn't exist yet.
45      if (!optionElement) {
46        optionElement = document.createElement("option");
47        optionElement.id = optionId;
48        document
49          .querySelector("select[name=payment-method]")
50          .appendChild(optionElement);
51      }
52 
53      optionElement.value = paymentMethod.get("stripeId");
54      optionElement.text = `${paymentMethod.get("card").brand} •••• ${
55        paymentMethod.get("card").last4
56      } | Expires ${paymentMethod.get("card").exp_month}/${
57        paymentMethod.get("card").exp_year
58      }`;
59    }
60  };
61
62  const renderPayments = (payments) => {
63    for (let payment of payments) {
64      let liElement = document.getElementById(`payment-${payment.id}`);
65      if (!liElement) {
66        liElement = document.createElement("li");
67        liElement.id = `payment-${payment.id}`;
68      }
69
70      const paymentData = payment.get("data");
71      let content = "";
72      if (
73        paymentData.status === "new" ||
74        paymentData.status === "requires_confirmation"
75      ) {
76        content = `Creating Payment for ${formatAmount(
77          paymentData.amount,
78          paymentData.currency
79        )}`;
80      } else if (paymentData.status === "succeeded") {
81        const card = paymentData.charges.data[0].payment_method_details.card;
82        content = `Payment for ${formatAmount(
83          paymentData.amount,
84          paymentData.currency
85        )} on ${card.brand} card •••• ${card.last4} ${paymentData.status}!`;
86      } else {
87        content = `Payment for ${formatAmount(
88          paymentData.amount,
89          paymentData.currency
90        )} ${paymentData.status}`;
91      }
92      liElement.innerText = content;
93      document.querySelector("#payments-list").appendChild(liElement);
94    }
95  };
96
97  // Checks if user is already signed in on Parse
98  if (Parse.User.current() !== null) {
99    setCompleteCurrentUser();
100   // Hide auth screen and show payment fields
101   document.getElementById("auth").style.display = "none";
102   document.getElementById("content").style.display = "block";
103 }
104
105 // Toggle signin and signup forms
106 document
107   .querySelector("#signup-toggle")
108   .addEventListener("click", async (_event) => {
109     document.getElementById("auth-signin-form").style.display = "none";
110     document.getElementById("auth-signup-form").style.display = "block";
111     clearAuthFormFields();
112   });
113 document
114   .querySelector("#signin-toggle")
115   .addEventListener("click", async (_event) => {
116     document.getElementById("auth-signup-form").style.display = "none";
117     document.getElementById("auth-signin-form").style.display = "block";
118     clearAuthFormFields();
119   });
120 
121  // Clear auth form fields
122 const clearAuthFormFields = () => {
123   document
124     .querySelector("#auth")
125     .querySelectorAll("input")
126     .forEach((input) => (input.value = ""));
127 };
128 
129 // Handle auth forms
130 document
131   .querySelector("#auth-signin-form")
132   .addEventListener("submit", async (event) => {
133     event.preventDefault();
134     toggleAllButtonsEnabled(false);
135     const form = new FormData(event.target);
136     const email = form.get("email");
137     const password = form.get("password");
138
139    // Try to signin on Parse
140     try {
141       let user = await Parse.User.logIn(email, password);
142       if (user !== null) {
143         currentUser = user;
144         // Hide auth screen and show payment fields
145         document.getElementById("auth").style.display = "none";
146         document.getElementById("content").style.display = "block";
147         clearAuthFormFields();
148       }
149     } catch (error) {
150       alert(error);
151     }
152     toggleAllButtonsEnabled(true);
153   });
154 
155 document
156   .querySelector("#auth-signup-form")
157   .addEventListener("submit", async (event) => {
158     event.preventDefault();
159     toggleAllButtonsEnabled(false);
160     const form = new FormData(event.target);
161     const email = form.get("email");
162     const password = form.get("password");
163
164     // Try to signup on Parse
165     try {
166       let user = await Parse.User.signUp(email, password, { email: email });
167       // Cloud code to create Stripe user and intent
168       user = await Parse.Cloud.run("createStripeCustomer", { userId: user.id });
169       if (user !== null) {
170         currentUser = user;
171         // Hide auth screen and show payment fields
172         document.getElementById("auth").style.display = "none";
173         document.getElementById("content").style.display = "block";
174         clearAuthFormFields();
175       }
176     } catch (error) {
177       alert(error);
178     }
179     toggleAllButtonsEnabled(true);
180   });
181 
182 // Signout from Parse
183 document.querySelector("#signout").addEventListener("click", async (_event) => {
184   await Parse.User.logOut();
185   currentUser = null;
186   // Show auth screen and hide payment fields
187   document.getElementById("auth").style.display = "block";
188   document.getElementById("content").style.display = "none";
189 });
190
191 // Creates stripe card UI element
192 const elements = stripe.elements();
193 const cardElement = elements.create("card");
194 cardElement.mount("#card-element");
195
196 // Handle add new card form
197 document
198   .querySelector("#payment-method-form")
199   .addEventListener("submit", async (event) => {
200    event.preventDefault();
201     toggleAllButtonsEnabled(false);
202     if (!event.target.reportValidity()) {
203       return;
204     }
205    const form = new FormData(event.target);
206     const cardholderName = form.get("name");
207 
208     const result = await stripe.confirmCardSetup(
209       currentUser.get("setupSecret"),
210       {
211         payment_method: {
212           card: cardElement,
213           billing_details: {
214             name: cardholderName,
215           },
216         },
217       }
218     );
219 
220     if (result.error) {
221       alert(result.error.message);
222       toggleAllButtonsEnabled(true);
223       return null;
224     }
225
226     let setupIntent = result.setupIntent;
227 
228     // Cloud code to add new payment method
229     let cloudCodeResult = await Parse.Cloud.run("addNewPaymentMethod", {
230       userId: currentUser.id,
231       paymentMethodId: setupIntent.payment_method,
232     });
233 
234     toggleAllButtonsEnabled(true);
235     alert("Success on creating a new payment method!");
236
237     // Update payment method options
238     retrieveCurrentUserPaymentMethods();
239   });
240 
241 // Handles new payment form
242 document
243   .querySelector("#payment-form")
244   .addEventListener("submit", async (event) => {
245     event.preventDefault();
246     toggleAllButtonsEnabled(false);
247     const form = new FormData(event.target);
248     const amount = Number(form.get("amount"));
249     const currency = form.get("currency");
250     // Gets selected card option id
251     const paymentMethod = form.get("payment-method");
252     const paymentData = {
253       payment_method: paymentMethod,
254       currency,
255       amount: formatAmountForStripe(amount, currency),
256       status: "new",
257     };
258     // Cloud code to create new payment
259     let cloudCodeResult = await Parse.Cloud.run("createNewPayment", {
260       userId: currentUser.id,
261       paymentData: paymentData,
262     });
263 
264     toggleAllButtonsEnabled(true);
265     alert("Success on creating a new payment!");
266 
267     retrieveCurrentUserPayments();
268   });
269  
270 // Helper functions
271 const toggleAllButtonsEnabled = (enabledValue) => {
272   document
273     .querySelectorAll("button")
274     .forEach((button) => (button.disabled = !enabledValue));
275 };
276
277 const formatAmount = (amount, currency) => {
278   amount = zeroDecimalCurrency(amount, currency)
279     ? amount
280     : (amount / 100).toFixed(2);
281   return new Intl.NumberFormat("en-US", {
282     style: "currency",
283     currency,
284   }).format(amount);
285 };
286
287 // Format amount for Stripe
288 const formatAmountForStripe = (amount, currency) => {
289   return zeroDecimalCurrency(amount, currency)
290     ? amount
291     : Math.round(amount * 100);
292 };
293
294 // Check if we have a zero decimal currency
295 // https://stripe.com/docs/currencies#zero-decimal
296 const zeroDecimalCurrency = (amount, currency) => {
297   let numberFormat = new Intl.NumberFormat(["en-US"], {
298     style: "currency",
299     currency: currency,
300     currencyDisplay: "symbol",
301   });
302   const parts = numberFormat.formatToParts(amount);
303   let zeroDecimalCurrency = true;
304   for (let part of parts) {
305     if (part.type === "decimal") {
306       zeroDecimalCurrency = false;
307     }
308   }
309   return zeroDecimalCurrency;
310 };
```
:::

파일 상단에 Stripe 공개 키와 Parse 앱 ID 및 JS 키를 추가해야 합니다. 이 스크립트에서 확인하고 이해해야 할 주요 요소 중 일부입니다:

- 페이지의 올바른 부분을 렌더링하기 위해 스크립트를 처음 로드할 때 <font color="#2166ae">`Parse.User.current`</font> 메서드의 사용을 확인하십시오;
- Parse에서 작업을 수행할 폼 제출 액션 리스너, 예를 들어 로그인 또는 회원가입 및 Stripe 관련 객체를 생성하고 Back4App 데이터베이스에 저장하기 위해 Cloud Code 함수를 호출하는 것;
- 현재 사용자의 <font color="#2166ae">`Payment`</font> 및 <font color="#2166ae">`PaymentMethod`</font> 객체를 검색하기 위해 Parse에서 쿼리를 수행하는 “retrieve” 및 “return” 메서드.

앱을 테스트하기 전에 같은 디렉토리에 <font color="#2166ae">`app.css`</font>라는 CSS 파일에 다음 스타일시트를 추가하십시오:

```css
1   /* Back4App Guide */
2 
3   *,
4   *:before,
5   *:after {
6     margin: 0;
7     padding: 0;
8     box-sizing: inherit;
9   }
10
11  html {
12    font-family: sans-serif;
13    box-sizing: border-box;
14    outline: none;
15    overflow: auto;
16  }
17
18  body {
19    margin: 0;
20    background-color: #fff;
21  }
22  
23  h1,
24  h2,
25  h3,
26  h4,
27  h5,
28  h6 {
29    margin: 0;
30  }
31
32  p {
33    margin: 0;
34  }
35
36  .container {
37    width: 100%;
38    max-width: 600px;
39    margin: auto;
40    padding: 20px 0;
41  }
42  
43  .wrapper {
44   width: '90%';
45    align-self: 'center';
46  }
47
48  .header {
49    display: flex;
50    flex-direction: column;
51    align-items: center;
52    padding: 25px 0;
53    background-color: #208AEC;
54  }
55
56  .header_logo {
57    height: 55px;
58    margin-bottom: 20px;
59    object-fit: contain;
60  }
61  
62  .header_text_bold {
63    margin-bottom: 3px;
64    color: rgba(255, 255, 255, 0.9);
65    font-size: 16px;
66    font-weight: bold;
67  }
68  
69  .header_text {
70    color: rgba(255, 255, 255, 0.9);
71    font-size: 15px;
72  }
73
74  .flex_row {
75    display: flex;
76  }
77  
78  .flex_between {
79    display: flex;
80    align-items: center;
81    justify-content: space-between;
82  }
83
84  .form_wrapper {
85    margin-top: 20px;
86    margin-bottom: 10px;
87  }
88
89  .form_heading {
90    margin-bottom: 10px;
91  }
92
93  .form {
94    padding-bottom: 25px;
95    margin: 25px 0;
96    border-bottom: 1px solid rgba(0, 0, 0, 0.12);
97  }
98
99  .form_input {
100   display: block;
101   width: 100%;
102   height: 46px;
103   padding: 0 15px;
104   background-color: #e6e6e6;
105   border: 1px solid #ccc;
106   border-radius: 999px;
107   margin-bottom: 20px;
108   font-size: 16px;
109 }
110
111 .form_button {
112   display: block;
113   width: 100%;
114   height: 42px;
115   padding: 0 15px;
116   background-color: #208AEC;
117   border: 1px solid #208AEC;
118   border-radius: 999px;
119   color: #fff;
120   font-size: 16px;
121   cursor: pointer;
122 }
123
124  .form_hint {
125   display: block;
126   margin-top: 20px;
127   color: rgba(0, 0, 0, 0.5);
128   font-size: 16px;
129   text-align: center;
130   text-decoration-color: rgba(0, 0, 0, 0.4);
131 }
132
133 .card_element_wrapper {
134   padding: 13px 15px;
135   margin-bottom: 20px;
136   background-color: #e6e6e6;
137   border: 1px solid #ccc;
138   border-radius: 999px;
139 }
```

앱을 테스트하려면 [http-server 노드 패키지](https://github.com/http-party/http-server)와 같은 로컬 HTTP 서버를 사용하세요. 가입 후, 앱은 다음과 같아야 합니다:

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/zmw8j8fXi-Ghyk53M-7KG_image.png" size="80" width="800" height="673" position="center" showCaption="false"}

## 결론

위에서 설명한 가이드를 통해, Back4App에서 Cloud Code 기능을 사용하여 Stripe를 사용하고 간단한 JavaScript 앱에 결제를 통합할 수 있었습니다!

Stripe 통합 중 문제가 발생하거나 기능이 작동하지 않는 경우, 채팅을 통해 저희 팀에 문의해 주세요!
