AWS Lambda와 Stripe Webhook 통합

저는 지난 달 정도 동안 Stripe와 함께 일했으며 사람들을 난처하게 만드는 것처럼 보였던 주제 중 하나는 Lambda 함수에서 Stripe 웹훅을 처리하는 것이었습니다. 코드를 잘못 구성했기 때문에 처음에 이 문제를 발견했지만 API 게이트웨이 및 Lambda 프록시 구성 설정과는 관련이 없습니다. 특히 this GitHub issue 에서 다른 사람들이 겪었던 문제를 언급하고 있습니다.

내 엔드포인트를 API 게이트웨이 및 Lambda 프록시 통합으로 설정했습니다. Stripe에서 생성된 엔드포인트 URL을 구성하고 내 Stripe 보안 키와 웹훅 보안을 Secret Manager에 보관된 환경 변수로 Lambda에 전달했습니다. Stripe 대시보드에서 "Test Webhook"이벤트를 사용하려고 시도했지만 내가 달성해야 하는 것과 잘 작동하지 않는 더미 고객 및 가격 ID를 보냅니다. 어느 쪽이든 내 테스트 환경을 사용하여 전체 통합 및 온보딩 시퀀스를 재생함으로써 모든 것을 빠르게 시작하고 실행할 수 있었습니다.

웹훅을 확인하는 것은 충분히 쉽고 재미있는 통합 덕분에 통과할 수 있습니다. Here’s a link to what I followed from their side . 이것은 앞서 언급한 GitHub 문제에서 대부분의 사람들에게 고착점이었습니다.

원시 본문을 구문 분석하거나 요청을 문자열화해야 한다는 언급이 꽤 있었습니다. 저에게는 event.bodystripe.webhooks.constructEvent 함수에 전달하기만 하면 됩니다. 그게 다야.

Webhook 이벤트를 구성한 후에는 필요한 정보를 구문 분석하고 그에 따라 조치하는 일만 남았습니다. 필요한 것은 구독 및 가격 ID를 가져와서 프런트 엔드에서 검색할 수 있도록 데이터베이스에 저장하는 것이었습니다. This is what that Lambda handler looks like .

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const {
  updateUserSubscription,
  deleteUserSubscription,
} = require('./database');

exports.handler = async function (event, context, callback) {
  const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
  try {
    const requestId = event?.requestContext?.requestId;
    const sig = event?.headers['Stripe-Signature'];

    const stripeEvent = stripe.webhooks.constructEvent(event.body, sig, webhookSecret);
    const eventType = stripeEvent.type ? stripeEvent.type : '';
    // https://stripe.com/docs/api#event_object
    const jsonData = JSON.parse(event.body);

    console.log(`Event Type: ${eventType}`);
    console.log(jsonData);

    const subscriptionId = stripeEvent.data.object.id;
    const customerId = stripeEvent.data.object.customer;
    const priceId = stripeEvent.data.object.plan?.id;

    let customerEmail;
    customerEmail = stripeEvent.data.object['customer_details']?.email;
    if (!customerEmail) {
      const customer = await stripe.customers.retrieve(customerId);
      customerEmail = customer.email;
    }

    switch (eventType) {
      case 'customer.subscription.created':
      case 'customer.subscription.updated':
        await updateUserSubscription(
          customerEmail,
          subscriptionId,
          priceId,
        );
        break;
      case 'customer.subscription.deleted':
        await deleteUserSubscription(
          customerEmail,
        );
      default:
        console.log('Unhandled event type');
        console.log(stripeEvent.data.object);
        break;
    }

    const data = {
      statusCode: 200,
      body: JSON.stringify({
        received: true,
      }),
    };
    return data;
  } catch (uncaughtError) {
    console.error(uncaughtError);
    throw uncaughtError;
  }
}

좋은 웹페이지 즐겨찾기