Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
Menggunakan AWS Lambda resolver di AWS AppSync
Anda dapat menggunakan AWS Lambda dengan AWS AppSync untuk menyelesaikan bidang GraphQL apa pun. Misalnya, kueri GraphQL mungkin mengirim panggilan ke instance Amazon Relational Database Service RDS (Amazon), dan mutasi GraphQL mungkin menulis ke aliran Amazon Kinesis. Di bagian ini, kami akan menunjukkan cara menulis fungsi Lambda yang melakukan logika bisnis berdasarkan pemanggilan operasi lapangan GraphQL.
Buat fungsi Lambda
Contoh berikut menunjukkan fungsi Lambda ditulis dalam Node.js
(runtime: Node.js 18.x) yang melakukan operasi yang berbeda pada posting blog sebagai bagian dari aplikasi posting blog. Perhatikan bahwa kode harus disimpan dalam nama file dengan ekstensi.mis.
export const handler = async (event) => { console.log('Received event {}', JSON.stringify(event, 3)) const posts = { 1: { id: '1', title: 'First book', author: 'Author1', url: 'https://amazon.com/', content: 'SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1', ups: '100', downs: '10', }, 2: { id: '2', title: 'Second book', author: 'Author2', url: 'https://amazon.com', content: 'SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT', ups: '100', downs: '10', }, 3: { id: '3', title: 'Third book', author: 'Author3', url: null, content: null, ups: null, downs: null }, 4: { id: '4', title: 'Fourth book', author: 'Author4', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4', ups: '1000', downs: '0', }, 5: { id: '5', title: 'Fifth book', author: 'Author5', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT', ups: '50', downs: '0', }, } const relatedPosts = { 1: [posts['4']], 2: [posts['3'], posts['5']], 3: [posts['2'], posts['1']], 4: [posts['2'], posts['1']], 5: [], } console.log('Got an Invoke Request.') let result switch (event.field) { case 'getPost': return posts[event.arguments.id] case 'allPosts': return Object.values(posts) case 'addPost': // return the arguments back return event.arguments case 'addPostErrorWithData': result = posts[event.arguments.id] // attached additional error information to the post result.errorMessage = 'Error with the mutation, data has changed' result.errorType = 'MUTATION_ERROR' return result case 'relatedPosts': return relatedPosts[event.source.id] default: throw new Error('Unknown field, unable to resolve ' + event.field) } }
Fungsi Lambda ini mengambil posting dengan ID, menambahkan posting, mengambil daftar posting, dan mengambil posting terkait untuk posting tertentu.
catatan
Fungsi Lambda menggunakan switch
pernyataan event.field
untuk menentukan bidang mana yang sedang diselesaikan.
Buat fungsi Lambda ini menggunakan AWS Management Console.
Konfigurasikan sumber data untuk Lambda
Setelah Anda membuat fungsi Lambda, navigasikan ke GraphQL Anda API di AWS AppSync konsol, lalu pilih tab Sumber Data.
Pilih Buat sumber data, masukkan nama sumber data yang ramah (misalnya,Lambda
), dan kemudian untuk tipe sumber data, pilih AWS Lambda fungsi. Untuk Wilayah, pilih Wilayah yang sama dengan fungsi Anda. Untuk Fungsi ARN, pilih Amazon Resource Name (ARN) dari fungsi Lambda Anda.
Setelah memilih fungsi Lambda, Anda dapat membuat peran new AWS Identity and Access Management (IAM) (yang AWS AppSync menetapkan izin yang sesuai) atau memilih peran yang ada yang memiliki kebijakan sebaris berikut:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": "arn:aws:lambda:REGION:ACCOUNTNUMBER:function/LAMBDA_FUNCTION" } ] }
Anda juga harus mengatur hubungan kepercayaan dengan AWS AppSync IAM peran sebagai berikut:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "appsync.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
Buat skema GraphQL
Sekarang sumber data terhubung ke fungsi Lambda Anda, buat skema GraphQL.
Dari editor skema di AWS AppSync konsol, pastikan skema Anda cocok dengan skema berikut:
schema { query: Query mutation: Mutation } type Query { getPost(id:ID!): Post allPosts: [Post] } type Mutation { addPost(id: ID!, author: String!, title: String, content: String, url: String): Post! } type Post { id: ID! author: String! title: String content: String url: String ups: Int downs: Int relatedPosts: [Post] }
Konfigurasikan resolver
Setelah mendaftarkan sumber data Lambda dan skema GraphQL yang valid, Anda dapat menghubungkan bidang GraphQL ke sumber data Lambda menggunakan resolver.
Anda akan membuat resolver yang menggunakan runtime AWS AppSync JavaScript (APPSYNC_JS
) dan berinteraksi dengan fungsi Lambda Anda. Untuk mempelajari selengkapnya tentang menulis AWS AppSync resolver dan fungsi dengan JavaScript, lihat fitur JavaScript runtime untuk resolver dan fungsi.
Untuk informasi selengkapnya tentang template pemetaan Lambda, lihat referensi JavaScript fungsi resolver untuk Lambda.
Pada langkah ini, Anda melampirkan resolver ke fungsi Lambda untuk bidang berikut:getPost(id:ID!):
Post
,,, allPosts: [Post]
dan. addPost(id: ID!, author: String!, title: String,
content: String, url: String): Post!
Post.relatedPosts: [Post]
Dari editor Skema di AWS AppSync konsol, di panel Resolvers, pilih Lampirkan di sebelah bidang. getPost(id:ID!): Post
Pilih sumber data Lambda Anda. Selanjutnya, berikan kode berikut:
import { util } from '@aws-appsync/utils'; export function request(ctx) { const {source, args} = ctx return { operation: 'Invoke', payload: { field: ctx.info.fieldName, arguments: args, source }, }; } export function response(ctx) { return ctx.result; }
Kode resolver ini meneruskan nama bidang, daftar argumen, dan konteks tentang objek sumber ke fungsi Lambda saat memanggilnya. Pilih Simpan.
Anda telah berhasil melampirkan resolver pertama Anda. Ulangi operasi ini untuk bidang yang tersisa.
Uji GraphQL Anda API
Sekarang fungsi Lambda Anda terhubung ke resolver GraphQL, Anda dapat menjalankan beberapa mutasi dan kueri menggunakan konsol atau aplikasi klien.
Di sisi kiri AWS AppSync konsol, pilih Kueri, lalu tempel kode berikut:
addPost Mutasi
mutation AddPost { addPost( id: 6 author: "Author6" title: "Sixth book" url: "https://www.amazon.com/" content: "This is the book is a tutorial for using GraphQL with AWS AppSync." ) { id author title content url ups downs } }
getPost Permintaan
query GetPost { getPost(id: "2") { id author title content url ups downs } }
allPosts Permintaan
query AllPosts { allPosts { id author title content url ups downs relatedPosts { id title } } }
Mengembalikan kesalahan
Setiap resolusi bidang yang diberikan dapat mengakibatkan kesalahan. Dengan AWS AppSync, Anda dapat meningkatkan kesalahan dari sumber-sumber berikut:
-
Penangan respons penyelesai
-
Fungsi Lambda
Dari penangan respons resolver
Untuk meningkatkan kesalahan yang disengaja, Anda dapat menggunakan metode util.error
utilitas. Dibutuhkan argumenerrorMessage
, anerrorType
, dan data
nilai opsional. data
Ini berguna untuk mengembalikan data tambahan kembali ke klien ketika terjadi kesalahan. data
Objek ditambahkan ke errors
dalam respons akhir GraphQL.
Contoh berikut menunjukkan cara menggunakannya dalam penangan respon Post.relatedPosts: [Post]
resolver.
// the Post.relatedPosts response handler export function response(ctx) { util.error("Failed to fetch relatedPosts", "LambdaFailure", ctx.result) return ctx.result; }
Ini menghasilkan respons GraphQL yang mirip dengan yang berikut:
{ "data": { "allPosts": [ { "id": "2", "title": "Second book", "relatedPosts": null }, ... ] }, "errors": [ { "path": [ "allPosts", 0, "relatedPosts" ], "errorType": "LambdaFailure", "locations": [ { "line": 5, "column": 5 } ], "message": "Failed to fetch relatedPosts", "data": [ { "id": "2", "title": "Second book" }, { "id": "1", "title": "First book" } ] } ] }
allPosts[0].relatedPosts
Dimana nol karena kesalahan danerrorMessage
,errorType
, dan data
hadir dalam data.errors[0]
objek.
Dari fungsi Lambda
AWS AppSync juga memahami kesalahan yang dilemparkan fungsi Lambda. Model pemrograman Lambda memungkinkan Anda meningkatkan kesalahan yang ditangani. Jika fungsi Lambda melempar kesalahan, AWS AppSync gagal menyelesaikan bidang saat ini. Hanya pesan kesalahan yang dikembalikan dari Lambda yang disetel dalam respons. Saat ini, Anda tidak dapat meneruskan data asing apa pun kembali ke klien dengan memunculkan kesalahan dari fungsi Lambda.
catatan
Jika fungsi Lambda Anda memunculkan kesalahan yang tidak tertangani, AWS AppSync gunakan pesan kesalahan yang disetel Lambda.
Fungsi Lambda berikut menimbulkan kesalahan:
export const handler = async (event) => { console.log('Received event {}', JSON.stringify(event, 3)) throw new Error('I always fail.') }
Kesalahan diterima di handler respons Anda. Anda dapat mengirimnya kembali dalam respons GraphQL dengan menambahkan kesalahan ke respons dengan. util.appendError
Untuk melakukannya, ubah penangan respons AWS AppSync fungsi Anda menjadi ini:
// the lambdaInvoke response handler export function response(ctx) { const { error, result } = ctx; if (error) { util.appendError(error.message, error.type, result); } return result; }
Ini mengembalikan respon GraphQL mirip dengan berikut:
{ "data": { "allPosts": null }, "errors": [ { "path": [ "allPosts" ], "data": null, "errorType": "Lambda:Unhandled", "errorInfo": null, "locations": [ { "line": 2, "column": 3, "sourceName": null } ], "message": "I fail. always" } ] }
Kasus penggunaan lanjutan: Batching
Fungsi Lambda dalam contoh ini memiliki relatedPosts
bidang yang mengembalikan daftar posting terkait untuk posting tertentu. Dalam contoh kueri, pemanggilan allPosts
bidang dari fungsi Lambda mengembalikan lima posting. Karena kami menetapkan bahwa kami juga ingin menyelesaikan relatedPosts
untuk setiap posting yang dikembalikan, operasi relatedPosts
lapangan dipanggil lima kali.
query { allPosts { // 1 Lambda invocation - yields 5 Posts id author title content url ups downs relatedPosts { // 5 Lambda invocations - each yields 5 posts id title } } }
Meskipun ini mungkin tidak terdengar substansif dalam contoh spesifik ini, pengambilan berlebihan yang diperparah ini dapat dengan cepat merusak aplikasi.
Jika Anda mengambil relatedPosts
lagi pada terkait yang dikembalikan Posts
dalam kueri yang sama, jumlah pemanggilan akan meningkat secara dramatis.
query { allPosts { // 1 Lambda invocation - yields 5 Posts id author title content url ups downs relatedPosts { // 5 Lambda invocations - each yield 5 posts = 5 x 5 Posts id title relatedPosts { // 5 x 5 Lambda invocations - each yield 5 posts = 25 x 5 Posts id title author } } } }
Dalam kueri yang relatif sederhana ini, AWS AppSync akan memanggil fungsi Lambda 1 + 5 + 25 = 31 kali.
Ini adalah tantangan yang cukup umum dan sering disebut masalah N+1 (dalam hal ini, N = 5), dan dapat menimbulkan peningkatan latensi dan biaya untuk aplikasi.
Salah satu pendekatan untuk memecahkan masalah ini adalah dengan mengumpulkan permintaan penyelesai bidang serupa bersama-sama. Dalam contoh ini, alih-alih memiliki fungsi Lambda menyelesaikan daftar posting terkait untuk satu posting tertentu, itu malah bisa menyelesaikan daftar posting terkait untuk kumpulan posting tertentu.
Untuk mendemonstrasikan ini, mari perbarui resolver relatedPosts
untuk menangani batching.
import { util } from '@aws-appsync/utils'; export function request(ctx) { const {source, args} = ctx return { operation: ctx.info.fieldName === 'relatedPosts' ? 'BatchInvoke' : 'Invoke', payload: { field: ctx.info.fieldName, arguments: args, source }, }; } export function response(ctx) { const { error, result } = ctx; if (error) { util.appendError(error.message, error.type, result); } return result; }
Kode sekarang mengubah operasi dari Invoke
BatchInvoke
saat fieldName
sedang diselesaikanrelatedPosts
. Sekarang, aktifkan batching pada fungsi di bagian Configure Batching. Atur ukuran batching maksimum yang disetel ke5
. Pilih Simpan.
Dengan perubahan ini, saat menyelesaikanrelatedPosts
, fungsi Lambda menerima yang berikut sebagai input:
[ { "field": "relatedPosts", "source": { "id": 1 } }, { "field": "relatedPosts", "source": { "id": 2 } }, ... ]
Ketika BatchInvoke
ditentukan dalam permintaan, fungsi Lambda menerima daftar permintaan dan mengembalikan daftar hasil.
Secara khusus, daftar hasil harus sesuai dengan ukuran dan urutan entri payload permintaan sehingga AWS AppSync dapat cocok dengan hasil yang sesuai.
Dalam contoh batching ini, fungsi Lambda mengembalikan sekumpulan hasil sebagai berikut:
[ [{"id":"2","title":"Second book"}, {"id":"3","title":"Third book"}], // relatedPosts for id=1 [{"id":"3","title":"Third book"}] // relatedPosts for id=2 ]
Anda dapat memperbarui kode Lambda Anda untuk menangani batching untuk: relatedPosts
export const handler = async (event) => { console.log('Received event {}', JSON.stringify(event, 3)) //throw new Error('I fail. always') const posts = { 1: { id: '1', title: 'First book', author: 'Author1', url: 'https://amazon.com/', content: 'SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1', ups: '100', downs: '10', }, 2: { id: '2', title: 'Second book', author: 'Author2', url: 'https://amazon.com', content: 'SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT', ups: '100', downs: '10', }, 3: { id: '3', title: 'Third book', author: 'Author3', url: null, content: null, ups: null, downs: null }, 4: { id: '4', title: 'Fourth book', author: 'Author4', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4', ups: '1000', downs: '0', }, 5: { id: '5', title: 'Fifth book', author: 'Author5', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT', ups: '50', downs: '0', }, } const relatedPosts = { 1: [posts['4']], 2: [posts['3'], posts['5']], 3: [posts['2'], posts['1']], 4: [posts['2'], posts['1']], 5: [], } if (!event.field && event.length){ console.log(`Got a BatchInvoke Request. The payload has ${event.length} items to resolve.`); return event.map(e => relatedPosts[e.source.id]) } console.log('Got an Invoke Request.') let result switch (event.field) { case 'getPost': return posts[event.arguments.id] case 'allPosts': return Object.values(posts) case 'addPost': // return the arguments back return event.arguments case 'addPostErrorWithData': result = posts[event.arguments.id] // attached additional error information to the post result.errorMessage = 'Error with the mutation, data has changed' result.errorType = 'MUTATION_ERROR' return result case 'relatedPosts': return relatedPosts[event.source.id] default: throw new Error('Unknown field, unable to resolve ' + event.field) } }
Mengembalikan kesalahan individu
Contoh sebelumnya menunjukkan bahwa dimungkinkan untuk mengembalikan satu kesalahan dari fungsi Lambda atau memunculkan kesalahan dari penangan respons Anda. Untuk pemanggilan batch, memunculkan kesalahan dari fungsi Lambda menandai seluruh batch sebagai gagal. Ini mungkin dapat diterima untuk skenario tertentu di mana terjadi kesalahan yang tidak dapat dipulihkan, seperti koneksi yang gagal ke penyimpanan data. Namun, dalam kasus di mana beberapa item dalam batch berhasil dan yang lainnya gagal, dimungkinkan untuk mengembalikan kesalahan dan data yang valid. Karena AWS AppSync memerlukan respons batch untuk mencantumkan elemen yang cocok dengan ukuran asli batch, Anda harus menentukan struktur data yang dapat membedakan data yang valid dari kesalahan.
Misalnya, jika fungsi Lambda diharapkan mengembalikan sekumpulan posting terkait, Anda dapat memilih untuk mengembalikan daftar Response
objek di mana setiap objek memiliki data opsional errorMessage, dan errorTypebidang. Jika errorMessagebidang ada, itu berarti terjadi kesalahan.
Kode berikut menunjukkan bagaimana Anda dapat memperbarui fungsi Lambda:
export const handler = async (event) => { console.log('Received event {}', JSON.stringify(event, 3)) // throw new Error('I fail. always') const posts = { 1: { id: '1', title: 'First book', author: 'Author1', url: 'https://amazon.com/', content: 'SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1', ups: '100', downs: '10', }, 2: { id: '2', title: 'Second book', author: 'Author2', url: 'https://amazon.com', content: 'SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT', ups: '100', downs: '10', }, 3: { id: '3', title: 'Third book', author: 'Author3', url: null, content: null, ups: null, downs: null }, 4: { id: '4', title: 'Fourth book', author: 'Author4', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4', ups: '1000', downs: '0', }, 5: { id: '5', title: 'Fifth book', author: 'Author5', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT', ups: '50', downs: '0', }, } const relatedPosts = { 1: [posts['4']], 2: [posts['3'], posts['5']], 3: [posts['2'], posts['1']], 4: [posts['2'], posts['1']], 5: [], } if (!event.field && event.length){ console.log(`Got a BatchInvoke Request. The payload has ${event.length} items to resolve.`); return event.map(e => { // return an error for post 2 if (e.source.id === '2') { return { 'data': null, 'errorMessage': 'Error Happened', 'errorType': 'ERROR' } } return {data: relatedPosts[e.source.id]} }) } console.log('Got an Invoke Request.') let result switch (event.field) { case 'getPost': return posts[event.arguments.id] case 'allPosts': return Object.values(posts) case 'addPost': // return the arguments back return event.arguments case 'addPostErrorWithData': result = posts[event.arguments.id] // attached additional error information to the post result.errorMessage = 'Error with the mutation, data has changed' result.errorType = 'MUTATION_ERROR' return result case 'relatedPosts': return relatedPosts[event.source.id] default: throw new Error('Unknown field, unable to resolve ' + event.field) } }
Perbarui kode relatedPosts
resolver:
import { util } from '@aws-appsync/utils'; export function request(ctx) { const {source, args} = ctx return { operation: ctx.info.fieldName === 'relatedPosts' ? 'BatchInvoke' : 'Invoke', payload: { field: ctx.info.fieldName, arguments: args, source }, }; } export function response(ctx) { const { error, result } = ctx; if (error) { util.appendError(error.message, error.type, result); } else if (result.errorMessage) { util.appendError(result.errorMessage, result.errorType, result.data) } else if (ctx.info.fieldName === 'relatedPosts') { return result.data } else { return result } }
Handler respons sekarang memeriksa kesalahan yang dikembalikan oleh fungsi Lambda Invoke
pada operasi, memeriksa kesalahan yang dikembalikan untuk item individual BatchInvoke
untuk operasi, dan akhirnya memeriksa. fieldName
UntukrelatedPosts
, fungsi kembaliresult.data
. Untuk semua bidang lainnya, fungsi hanya kembaliresult
. Misalnya, lihat kueri di bawah ini:
query AllPosts { allPosts { id title content url ups downs relatedPosts { id } author } }
Query ini mengembalikan respon GraphQL mirip dengan berikut:
{ "data": { "allPosts": [ { "id": "1", "relatedPosts": [ { "id": "4" } ] }, { "id": "2", "relatedPosts": null }, { "id": "3", "relatedPosts": [ { "id": "2" }, { "id": "1" } ] }, { "id": "4", "relatedPosts": [ { "id": "2" }, { "id": "1" } ] }, { "id": "5", "relatedPosts": [] } ] }, "errors": [ { "path": [ "allPosts", 1, "relatedPosts" ], "data": null, "errorType": "ERROR", "errorInfo": null, "locations": [ { "line": 4, "column": 5, "sourceName": null } ], "message": "Error Happened" } ] }
Mengkonfigurasi ukuran batching maksimum
Untuk mengonfigurasi ukuran batching maksimum pada resolver, gunakan perintah berikut di (): AWS Command Line Interface AWS CLI
$ aws appsync create-resolver --api-id <api-id> --type-name Query --field-name relatedPosts \ --code "<code-goes-here>" \ --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \ --data-source-name "<lambda-datasource>" \ --max-batch-size X
catatan
Saat menyediakan template pemetaan permintaan, Anda harus menggunakan BatchInvoke
operasi untuk menggunakan batching.