

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Tutorial: Membuat titik akhir webhook menggunakan URL fungsi Lambda
<a name="urls-webhook-tutorial"></a>

Dalam tutorial ini, Anda membuat URL fungsi Lambda untuk mengimplementasikan endpoint webhook. Webhook adalah komunikasi ringan yang digerakkan oleh peristiwa yang secara otomatis mengirimkan data antar aplikasi menggunakan HTTP. Anda dapat menggunakan webhook untuk menerima pembaruan langsung tentang peristiwa yang terjadi di sistem lain, seperti ketika pelanggan baru mendaftar di situs web, pembayaran diproses, atau file diunggah.

Dengan Lambda, webhook dapat diimplementasikan menggunakan fungsi Lambda atau API Gateway. URLs Fungsi URLs adalah pilihan yang baik untuk webhook sederhana yang tidak memerlukan fitur seperti otorisasi lanjutan atau validasi permintaan.

**Tip**  
Jika Anda tidak yakin solusi mana yang terbaik untuk kasus penggunaan khusus Anda, lihat[Pilih metode untuk menjalankan fungsi Lambda Anda menggunakan permintaan HTTP](furls-http-invoke-decision.md).

## Prasyarat
<a name="urls-webhook-tutorial-prereqs"></a>

Untuk menyelesaikan tutorial ini, Anda harus memiliki Python (versi 3.8 atau yang lebih baru) atau Node.js (versi 18 atau lebih baru) diinstal pada mesin lokal Anda.

Untuk menguji titik akhir menggunakan permintaan HTTP, tutorial menggunakan [curl](https://curl.se/), alat baris perintah yang dapat Anda gunakan untuk mentransfer data menggunakan berbagai protokol jaringan. Lihat [dokumentasi curl](https://curl.se/docs/install.html) untuk mempelajari cara menginstal alat jika Anda belum memilikinya.

## Buat fungsi Lambda
<a name="urls-webhook-tutorial-function"></a>

Pertama buat fungsi Lambda yang berjalan ketika permintaan HTTP dikirim ke titik akhir webhook Anda. Dalam contoh ini, aplikasi pengiriman mengirimkan pembaruan setiap kali pembayaran dikirimkan dan menunjukkan di badan permintaan HTTP apakah pembayaran berhasil. Fungsi Lambda mem-parsing permintaan dan mengambil tindakan sesuai dengan status pembayaran. Dalam contoh ini, kode hanya mencetak ID pesanan untuk pembayaran, tetapi dalam aplikasi nyata, Anda dapat menambahkan pesanan ke database atau mengirim pemberitahuan.

Fungsi ini juga mengimplementasikan metode otentikasi yang paling umum digunakan untuk webhook, otentikasi pesan berbasis hash (HMAC). Dengan metode ini, aplikasi pengirim dan penerima berbagi kunci rahasia. Aplikasi pengiriman menggunakan algoritma hashing untuk menghasilkan tanda tangan unik menggunakan kunci ini bersama dengan konten pesan, dan menyertakan tanda tangan dalam permintaan webhook sebagai header HTTP. Aplikasi penerima kemudian mengulangi langkah ini, menghasilkan tanda tangan menggunakan kunci rahasia, dan membandingkan nilai yang dihasilkan dengan tanda tangan yang dikirim di header permintaan. Jika hasilnya cocok, permintaan dianggap sah. 

Buat fungsi menggunakan konsol Lambda dengan runtime Python atau Node.js.

------
#### [ Python ]

**Buat fungsi Lambda**

1. Buka [halaman Fungsi](https://console.aws.amazon.com/lambda/home#/functions) di konsol Lambda.

1. Buat fungsi dasar 'Hello world' dengan melakukan hal berikut:

   1. Pilih **Buat fungsi**.

   1. Pilih **Penulis dari awal**.

   1. Untuk **Nama fungsi**, masukkan **myLambdaWebhook**.

   1. Untuk **Runtime**, pilih **python3.14**.

   1. Pilih **Buat fungsi**.

1. Di panel **Sumber kode**, ganti kode yang ada dengan menyalin dan menempelkan berikut ini:

   ```
   import json
   import hmac
   import hashlib
   import os
   
   def lambda_handler(event, context):
       
       # Get the webhook secret from environment variables
       webhook_secret = os.environ['WEBHOOK_SECRET']
       
       # Verify the webhook signature
       if not verify_signature(event, webhook_secret):
           return {
               'statusCode': 401,
               'body': json.dumps({'error': 'Invalid signature'})
           }
       
       try:
           # Parse the webhook payload
           payload = json.loads(event['body'])
           
           # Handle different event types
           event_type = payload.get('type')
           
           if event_type == 'payment.success':
               # Handle successful payment
               order_id = payload.get('orderId')
               print(f"Processing successful payment for order {order_id}")
               
               # Add your business logic here
               # For example, update database, send notifications, etc.
               
           elif event_type == 'payment.failed':
               # Handle failed payment
               order_id = payload.get('orderId')
               print(f"Processing failed payment for order {order_id}")
               
               # Add your business logic here
               
           else:
               print(f"Received unhandled event type: {event_type}")
           
           # Return success response
           return {
               'statusCode': 200,
               'body': json.dumps({'received': True})
           }
           
       except json.JSONDecodeError:
           return {
               'statusCode': 400,
               'body': json.dumps({'error': 'Invalid JSON payload'})
           }
       except Exception as e:
           print(f"Error processing webhook: {e}")
           return {
               'statusCode': 500,
               'body': json.dumps({'error': 'Internal server error'})
           }
   
   def verify_signature(event, webhook_secret):
       """
       Verify the webhook signature using HMAC
       """
       try:
           # Get the signature from headers
           signature = event['headers'].get('x-webhook-signature')
   
           if not signature:
               print("Error: Missing webhook signature in headers")
               return False
           
           # Get the raw body (return an empty string if the body key doesn't exist)
           body = event.get('body', '')
           
           # Create HMAC using the secret key
           expected_signature = hmac.new(
               webhook_secret.encode('utf-8'),
               body.encode('utf-8'),
               hashlib.sha256
           ).hexdigest()
           
           # Compare the expected signature with the received signature to authenticate the message
           is_valid = hmac.compare_digest(signature, expected_signature)
           if not is_valid:
               print(f"Error: Invalid signature. Received: {signature}, Expected: {expected_signature}")
               return False
               
           return True
       except Exception as e:
           print(f"Error verifying signature: {e}")
           return False
   ```

1. Di bagian **DEPLOY**, pilih **Deploy** untuk memperbarui kode fungsi Anda.

------
#### [ Node.js ]

**Buat fungsi Lambda**

1. Buka [halaman Fungsi](https://console.aws.amazon.com/lambda/home#/functions) di konsol Lambda.

1. Buat fungsi dasar 'Hello world' dengan melakukan hal berikut:

   1. Pilih **Buat fungsi**.

   1. Pilih **Penulis dari awal**.

   1. Untuk **Nama fungsi**, masukkan **myLambdaWebhook**.

   1. Untuk **Runtime**, pilih **nodejs24.x**.

   1. Pilih **Buat fungsi**.

1. Di panel **Sumber kode**, ganti kode yang ada dengan menyalin dan menempelkan berikut ini:

   ```
   import crypto from 'crypto';
   
   export const handler = async (event, context) => {
       // Get the webhook secret from environment variables
       const webhookSecret = process.env.WEBHOOK_SECRET;
   
       // Verify the webhook signature
       if (!verifySignature(event, webhookSecret)) {
           return {
               statusCode: 401,
               body: JSON.stringify({ error: 'Invalid signature' })
           };
       }
   
       try {
           // Parse the webhook payload
           const payload = JSON.parse(event.body);
   
           // Handle different event types
           const eventType = payload.type;
   
           switch (eventType) {
               case 'payment.success': {
                   // Handle successful payment
                   const orderId = payload.orderId;
                   console.log(`Processing successful payment for order ${orderId}`);
   
                   // Add your business logic here
                   // For example, update database, send notifications, etc.
                   break;
               }
   
               case 'payment.failed': {
                   // Handle failed payment
                   const orderId = payload.orderId;
                   console.log(`Processing failed payment for order ${orderId}`);
   
                   // Add your business logic here
                   break;
               }
   
               default:
                   console.log(`Received unhandled event type: ${eventType}`);
           }
   
           // Return success response
           return {
               statusCode: 200,
               body: JSON.stringify({ received: true })
           };
   
       } catch (error) {
           if (error instanceof SyntaxError) {
               // Handle JSON parsing errors
               return {
                   statusCode: 400,
                   body: JSON.stringify({ error: 'Invalid JSON payload' })
               };
           }
   
           // Handle all other errors
           console.error('Error processing webhook:', error);
           return {
               statusCode: 500,
               body: JSON.stringify({ error: 'Internal server error' })
           };
       }
   };
   
   // Verify the webhook signature using HMAC
   
   const verifySignature = (event, webhookSecret) => {
       try {
           // Get the signature from headers
           const signature = event.headers['x-webhook-signature'];
     
           if (!signature) {
               console.log('No signature found in headers:', event.headers);
               return false;
           }
     
           // Get the raw body (return an empty string if the body key doesn't exist)
           const body = event.body || '';
     
           // Create HMAC using the secret key
           const hmac = crypto.createHmac('sha256', webhookSecret);
           const expectedSignature = hmac.update(body).digest('hex');
     
           // Compare expected and received signatures
           const isValid = signature === expectedSignature;
           if (!isValid) {
               console.log(`Invalid signature. Received: ${signature}, Expected: ${expectedSignature}`);
               return false;
           }
           
           return true;
       } catch (error) {
           console.error('Error during signature verification:', error);
           return false;
       }
     };
   ```

1. Di bagian **DEPLOY**, pilih **Deploy** untuk memperbarui kode fungsi Anda.

------

## Buat kunci rahasia
<a name="urls-webhook-tutorial-key"></a>

Untuk fungsi Lambda untuk mengotentikasi permintaan webhook, ia menggunakan kunci rahasia yang dibagikan dengan aplikasi panggilan. Dalam contoh ini, kunci disimpan dalam variabel lingkungan. Dalam aplikasi produksi, jangan sertakan informasi sensitif seperti kata sandi dalam kode fungsi Anda. Sebagai gantinya, [buat AWS Secrets Manager rahasia](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html) dan kemudian [gunakan ekstensi AWS Parameter dan Rahasia Lambda](with-secrets-manager.md) untuk mengambil kredensil Anda di fungsi Lambda Anda.

**Buat dan simpan kunci rahasia webhook**

1. Hasilkan string acak yang panjang menggunakan generator nomor acak yang aman secara kriptografis. Anda dapat menggunakan cuplikan kode berikut dengan Python atau Node.js untuk menghasilkan dan mencetak rahasia 32 karakter, atau menggunakan metode pilihan Anda sendiri.

------
#### [ Python ]

**Example kode untuk menghasilkan rahasia**  

   ```
   import secrets
   webhook_secret = secrets.token_urlsafe(32)
   print(webhook_secret)
   ```

------
#### [ Node.js ]

**Example kode untuk menghasilkan rahasia (format modul ES)**  

   ```
   import crypto from 'crypto';
   let webhookSecret = crypto.randomBytes(32).toString('base64');
   console.log(webhookSecret)
   ```

------

1. Simpan string yang Anda hasilkan sebagai variabel lingkungan untuk fungsi Anda dengan melakukan hal berikut:

   1. Di tab **Konfigurasi** untuk fungsi Anda, pilih **variabel Lingkungan**.

   1. Pilih **Edit**.

   1. Pilih **Tambahkan variabel lingkungan**.

   1. Untuk **Kunci**, masukkan**WEBHOOK\$1SECRET**, lalu untuk **Nilai**, masukkan rahasia yang Anda buat di langkah sebelumnya.

   1. Pilih **Simpan**.

Anda harus menggunakan rahasia ini lagi nanti di tutorial untuk menguji fungsi Anda, jadi catat sekarang.

## Buat titik akhir URL fungsi
<a name="urls-webhook-tutorial-furl"></a>

Buat titik akhir untuk webhook Anda menggunakan URL fungsi Lambda. Karena Anda menggunakan jenis autentikasi `NONE` untuk membuat titik akhir dengan akses publik, siapa pun yang memiliki URL dapat memanggil fungsi Anda. Untuk mempelajari lebih lanjut tentang mengontrol akses ke fungsi URLs, lihat[Kontrol akses ke fungsi Lambda URLs](urls-auth.md). Jika Anda memerlukan opsi otentikasi lanjutan untuk webhook Anda, pertimbangkan untuk menggunakan API Gateway.

**Buat titik akhir URL fungsi**

1. Di tab **Konfigurasi** untuk fungsi Anda, pilih **URL Fungsi**.

1. Pilih **Buat URL fungsi**.

1. Untuk **jenis Auth**, pilih **NONE**.

1. Pilih **Simpan**.

Titik akhir untuk URL fungsi yang baru saja Anda buat ditampilkan di panel **URL Fungsi**. Salin titik akhir untuk digunakan nanti dalam tutorial.

## Uji fungsi di konsol
<a name="urls-webhook-tutorial-test-console"></a>

Sebelum menggunakan permintaan HTTP untuk menjalankan fungsi Anda menggunakan titik akhir URL, uji di konsol untuk mengonfirmasi kode Anda berfungsi seperti yang diharapkan.

Untuk memverifikasi fungsi di konsol, pertama-tama Anda menghitung tanda tangan webhook menggunakan rahasia yang Anda buat sebelumnya dalam tutorial dengan payload JSON pengujian berikut:

```
{
    "type": "payment.success", 
    "orderId": "1234",
    "amount": "99.99"
}
```

Gunakan salah satu contoh kode Python atau Node.js berikut untuk menghitung tanda tangan webhook menggunakan rahasia Anda sendiri.

------
#### [ Python ]

**Hitung tanda tangan webhook**

1. Simpan kode berikut sebagai file bernama`calculate_signature.py`. Ganti rahasia webhook dalam kode dengan nilai Anda sendiri.

   ```
   import secrets
   import hmac
   import json
   import hashlib
   
   webhook_secret = "arlbSDCP86n_1H90s0fL_Qb2NAHBIBQOyGI0X4Zay4M"
   
   body = json.dumps({"type": "payment.success", "orderId": "1234", "amount": "99.99"})
   
   signature = hmac.new(
               webhook_secret.encode('utf-8'),
               body.encode('utf-8'),
               hashlib.sha256
           ).hexdigest()
   
   print(signature)
   ```

1. Hitung tanda tangan dengan menjalankan perintah berikut dari direktori yang sama tempat Anda menyimpan kode. Salin tanda tangan output kode.

   ```
   python calculate_signature.py
   ```

------
#### [ Node.js ]

**Hitung tanda tangan webhook**

1. Simpan kode berikut sebagai file bernama`calculate_signature.mjs`. Ganti rahasia webhook dalam kode dengan nilai Anda sendiri.

   ```
   import crypto from 'crypto';
   
   const webhookSecret = "arlbSDCP86n_1H90s0fL_Qb2NAHBIBQOyGI0X4Zay4M"
   const body = "{\"type\": \"payment.success\", \"orderId\": \"1234\", \"amount\": \"99.99\"}";
   
   let hmac = crypto.createHmac('sha256', webhookSecret);
   let signature = hmac.update(body).digest('hex');
   
   console.log(signature);
   ```

1. Hitung tanda tangan dengan menjalankan perintah berikut dari direktori yang sama tempat Anda menyimpan kode. Salin tanda tangan output kode.

   ```
   node calculate_signature.mjs
   ```

------

Anda sekarang dapat menguji kode fungsi Anda menggunakan permintaan HTTP pengujian di konsol.

**Uji fungsi di konsol**

1. Pilih tab **Kode** untuk fungsi Anda.

1. Di bagian **TEST EVENTS**, pilih **Create new test event**

1. Untuk **Nama Acara**, masukkan**myEvent**.

1. Ganti JSON yang ada dengan menyalin dan menempelkan berikut ini ke panel **Event** JSON. Ganti tanda tangan webhook dengan nilai yang Anda hitung pada langkah sebelumnya.

   ```
   {
     "headers": {
       "Content-Type": "application/json",
       "x-webhook-signature": "2d672e7a0423fab740fbc040e801d1241f2df32d2ffd8989617a599486553e2a"
     },
     "body": "{\"type\": \"payment.success\", \"orderId\": \"1234\", \"amount\": \"99.99\"}"
   }
   ```

1. Pilih **Simpan**.

1. Pilih **Panggil**.

   Anda akan melihat output yang serupa dengan yang berikut:

------
#### [ Python ]

   ```
   Status: Succeeded
   Test Event Name: myEvent
   
   Response:
   {
     "statusCode": 200,
     "body": "{\"received\": true}"
   }
   
   Function Logs:
   START RequestId: 50cc0788-d70e-453a-9a22-ceaa210e8ac6 Version: $LATEST
   Processing successful payment for order 1234
   END RequestId: 50cc0788-d70e-453a-9a22-ceaa210e8ac6
   REPORT RequestId: 50cc0788-d70e-453a-9a22-ceaa210e8ac6	Duration: 1.55 ms	Billed Duration: 2 ms	Memory Size: 128 MB	Max Memory Used: 36 MB	Init Duration: 136.32 ms
   ```

------
#### [ Node.js ]

   ```
   Status: Succeeded
   Test Event Name: myEvent
   
   Response:
   {
     "statusCode": 200,
     "body": "{\"received\":true}"
   }
   
   Function Logs:
   START RequestId: e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4 Version: $LATEST
   2025-01-10T18:05:42.062Z	e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4	INFO	Processing successful payment for order 1234
   END RequestId: e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4
   REPORT RequestId: e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4	Duration: 60.10 ms	Billed Duration: 61 ms	Memory Size: 128 MB	Max Memory Used: 72 MB	Init Duration: 174.46 ms
   
   Request ID: e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4
   ```

------

## Uji fungsi menggunakan permintaan HTTP
<a name="urls-webhook-tutorial-test-curl"></a>

Gunakan alat baris perintah curl untuk menguji titik akhir webhook Anda.

**Uji fungsi menggunakan permintaan HTTP**

1. Dalam program terminal atau shell, jalankan perintah curl berikut. Ganti URL dengan nilai untuk titik akhir URL fungsi Anda sendiri dan ganti tanda tangan webhook dengan tanda tangan yang Anda hitung menggunakan kunci rahasia Anda sendiri.

   ```
   curl -X POST https://ryqgmbx5xjzxahif6frvzikpre0bpvpf.lambda-url.us-west-2.on.aws/ \
   -H "Content-Type: application/json" \
   -H "x-webhook-signature: d5f52b76ffba65ff60ea73da67bdf1fc5825d4db56b5d3ffa0b64b7cb85ef48b" \
   -d '{"type": "payment.success", "orderId": "1234", "amount": "99.99"}'
   ```

   Anda akan melihat output berikut:

   ```
   {"received": true}
   ```

1. Periksa CloudWatch log untuk fungsi Anda untuk mengonfirmasinya mengurai muatan dengan benar dengan melakukan hal berikut:

   1. Buka halaman [grup Log](https://console.aws.amazon.com/cloudwatch/home#logsV2:log-groups) di CloudWatch konsol Amazon.

   1. Pilih grup log fungsi Anda (`/aws/lambda/myLambdaWebhook`).

   1. Pilih aliran log yang terbaru.

      Anda akan melihat output yang mirip dengan yang berikut di log fungsi Anda:

------
#### [ Python ]

      ```
      Processing successful payment for order 1234
      ```

------
#### [ Node.js ]

      ```
      2025-01-10T18:05:42.062Z e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4 INFO Processing successful payment for order 1234
      ```

------

1. Konfirmasikan bahwa kode Anda mendeteksi tanda tangan yang tidak valid dengan menjalankan perintah curl berikut. Ganti URL dengan titik akhir URL fungsi Anda sendiri.

   ```
   curl -X POST https://ryqgmbx5xjzxahif6frvzikpre0bpvpf.lambda-url.us-west-2.on.aws/ \
   -H "Content-Type: application/json" \
   -H "x-webhook-signature: abcdefg" \
   -d '{"type": "payment.success", "orderId": "1234", "amount": "99.99"}'
   ```

   Anda akan melihat output berikut:

   ```
   {"error": "Invalid signature"}
   ```

## Bersihkan sumber daya Anda
<a name="urls-webhook-tutorial-cleanup"></a>

Sekarang Anda dapat menghapus sumber daya yang Anda buat untuk tutorial ini, kecuali Anda ingin mempertahankannya. Dengan menghapus AWS sumber daya yang tidak lagi Anda gunakan, Anda mencegah tagihan yang tidak perlu ke Anda Akun AWS.

**Untuk menghapus fungsi Lambda**

1. Buka [halaman Fungsi](https://console.aws.amazon.com/lambda/home#/functions) di konsol Lambda.

1. Pilih fungsi yang Anda buat.

1. Pilih **Tindakan**, **Hapus**.

1. Ketik **confirm** kolom input teks dan pilih **Hapus**.

Saat Anda membuat fungsi Lambda di konsol, Lambda juga membuat [peran eksekusi](lambda-intro-execution-role.md) untuk fungsi Anda.

**Untuk menghapus peran eksekusi**

1. Buka [halaman Peran](https://console.aws.amazon.com/iam/home#/roles) dari konsol IAM.

1. Pilih peran eksekusi yang dibuat Lambda. Peran memiliki format nama`myLambdaWebhook-role-<random string>`.

1. Pilih **Hapus**.

1. Masukkan nama peran di bidang input teks dan pilih **Hapus**.