결제 처리를 위한 API 추가

이제 결제 처리를 위한 API를 만들어 보겠습니다. 이 API는 Stripe 토큰과 사용자가 저장하려는 노트의 개수를 받습니다.

결제 람다 추가하기

먼저 Stripe npm 패키지를 설치합니다.

Change indicator 프로젝트의 packages/functions/ 디렉토리에서 다음 명령어를 실행하세요.

$ npm install stripe

Change indicator packages/functions/src/billing.ts 파일을 생성하고 다음 내용을 추가하세요.

import Stripe from "stripe";
import { Resource } from "sst";
import { Util } from "@notes/core/util";
import { Billing } from "@notes/core/billing";

export const main = Util.handler(async (event) => {
  const { storage, source } = JSON.parse(event.body || "{}");
  const amount = Billing.compute(storage);
  const description = "Scratch charge";

  const stripe = new Stripe(
    // 비밀 키 로드
    Resource.StripeSecretKey.value,
    { apiVersion: "2024-06-20" }
  );

  await stripe.charges.create({
    source,
    amount,
    description,
    currency: "usd",
  });

  return JSON.stringify({ status: true });
});

대부분의 코드는 직관적이지만, 간단히 살펴보겠습니다:

  • 요청 본문에서 storagesource를 가져옵니다. storage는 사용자가 계정에 저장하려는 노트의 수이고, source는 결제할 카드의 Stripe 토큰입니다.

  • Billing.compute(storage) 함수를 사용하여 저장할 노트 수에 따라 사용자에게 청구할 금액을 계산합니다. 이 함수는 곧 추가할 예정입니다.

  • Stripe 비밀 키를 사용해 새로운 Stripe 객체를 생성합니다. 이 키는 이전 장에서 설정한 비밀 값에서 가져옵니다. 작성 시점에는 apiVersion 2024-06-20을 사용하고 있지만, 최신 버전은 Stripe 문서에서 확인할 수 있습니다.

  • 마지막으로 stripe.charges.create() 함수를 사용해 사용자에게 결제를 요청하고, 모든 과정이 성공적으로 완료되면 요청에 응답합니다.

비즈니스 로직 추가하기

이제 Billing.compute 함수를 구현해 보겠습니다. 이 함수는 우리 앱의 주요 _비즈니스 로직_입니다.

Change indicator packages/core/src/billing/index.ts 파일을 생성하고 다음 코드를 추가하세요.

export module Billing {
  export function compute(storage: number) {
    const rate = storage <= 10 ? 4 : storage <= 100 ? 2 : 1;
    return rate * storage * 100;
  }
}

_모듈_은 비즈니스 로직을 조직화하는 좋은 방법입니다. 앱의 다양한 _도메인_에 대해 모듈을 생성하는 것이 좋습니다. 이는 도메인 주도 설계의 기본 원칙을 따릅니다.

compute 함수는 사용자가 10개 이하의 노트를 저장하려면 노트당 $4를 청구하고, 11개에서 100개 사이의 노트는 노트당 $2, 100개 이상은 노트당 $1을 청구한다는 의미입니다. Stripe는 금액을 페니(통화의 가장 작은 단위)로 제공할 것을 요구하므로 결과에 100을 곱합니다.

분명히, 우리의 서버리스 인프라는 저렴할 수 있지만 서비스는 그렇지 않네요!

라우트 추가하기

빌링 API를 위한 새로운 라우트를 추가해 보겠습니다.

Change indicator infra/api.ts 파일에서 DELETE /notes/{id} 라우트 아래에 다음 코드를 추가하세요.

api.route("POST /billing", "packages/functions/src/billing.main");

변경 사항 배포하기

터미널로 이동하면 변경 사항이 배포되고 있는 것을 확인할 수 있습니다.

새로운 API 스택이 배포된 것을 확인할 수 있습니다.

+  Complete
   Api: https://5bv7x0iuga.execute-api.us-east-1.amazonaws.com
   ...

Billing API 테스트하기

이제 Billing API 설정이 완료되었으니, 로컬 환경에서 간단히 테스트해 보겠습니다.

이전 챕터에서 사용한 동일한 CLI를 사용할 것입니다.

Change indicator 터미널에서 다음 명령어를 실행하세요.

$ npx aws-api-gateway-cli-test \
--username='admin@example.com' \
--password='Passw0rd!' \
--user-pool-id='<USER_POOL_ID>' \
--app-client-id='<USER_POOL_CLIENT_ID>' \
--cognito-region='<COGNITO_REGION>' \
--identity-pool-id='<IDENTITY_POOL_ID>' \
--invoke-url='<API_ENDPOINT>' \
--api-gateway-region='<API_REGION>' \
--path-template='/billing' \
--method='POST' \
--body='{"source":"tok_visa","storage":21}'

여기서는 Stripe 테스트 토큰인 tok_visa와 저장하려는 노트의 개수 21로 테스트합니다. Stripe 테스트 카드와 토큰에 대한 자세한 내용은 Stripe API 문서에서 확인할 수 있습니다.

명령어가 성공적으로 실행되면, 응답은 다음과 비슷하게 나타납니다.

Authenticating with User Pool
Getting temporary credentials
Making API request
{ status: 200, statusText: 'OK', data: { status: true } }

변경 사항 커밋하기

Change indicator 변경 사항을 커밋하고 GitHub에 푸시해 보겠습니다.

$ git add .
$ git commit -m "결제 API 추가"
$ git push

이제 새로운 결제 API가 준비되었습니다. 서버리스 환경에서 유닛 테스트를 설정하는 방법을 살펴보겠습니다. 이를 통해 인프라와 비즈니스 로직이 올바르게 구성되었는지 확인할 수 있습니다.