

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# での GraphQL リゾルバーの組み合わせ AWS AppSync
<a name="tutorial-combining-graphql-resolvers"></a>

**注記**  
現在、主に APPSYNC\$1JS ランタイムとそのドキュメントをサポートしています。[こちら](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)にある APPSYNC\$1JS ランタイムとそのガイドの使用をご検討ください。

GraphQL スキーマのリゾルバーとフィールドには、非常に柔軟性の高い 1 対 1 の関係があります。データソースはスキーマとは独立にリゾルバーに設定されるため、ニーズに応じてスキーマ上で組み合わせやマッチングを行い、さまざまなデータソースを使用して GraphQL 型の解決や操作が行えます。

次のシナリオ例では、スキーマ内のデータソースを混在させて一致させる方法を示します。開始する前に、前のチュートリアルで説明したように AWS Lambda、、Amazon DynamoDB、Amazon OpenSearch Service のデータソースとリゾルバーの設定に精通しておくことをお勧めします。

## スキーマの例
<a name="example-schema"></a>

次のスキーマには、3 つの `Query` 処理と 3 つの `Mutation` 処理を含む `Post` という型が定義されています。

```
type Post {
    id: ID!
    author: String!
    title: String
    content: String
    url: String
    ups: Int
    downs: Int
    version: Int!
}

type Query {
    allPost: [Post]
    getPost(id: ID!): Post
    searchPosts: [Post]
}

type Mutation {
    addPost(
        id: ID!,
        author: String!,
        title: String,
        content: String,
        url: String
    ): Post
    updatePost(
        id: ID!,
        author: String!,
        title: String,
        content: String,
        url: String,
        ups: Int!,
        downs: Int!,
        expectedVersion: Int!
    ): Post
    deletePost(id: ID!): Post
}
```

この例では、合計 6 つのリゾルバーをアタッチします。考えられる方法の 1 つは、これらをすべて `Posts` という Amazon DynamoDB テーブルから取得することです。この場合、「[DynamoDB のリゾルバーのマッピングテンプレートリファレンス](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb)」で説明されているように、`AllPosts` はスキャンを実行し、`searchPosts` はクエリを実行します。ただし、Lambda または OpenSearch Service を使用してこれらの GraphQL クエリに解決させるなど、ビジネスニーズに応じて他の方法も使用できます。

## リゾルバーを使用してデータを変更する
<a name="alter-data-through-resolvers"></a>

DynamoDB (または Amazon Aurora) などのデータベースからクライアントに、一部の属性を変更した結果を返したい場合があります。クライアントでのタイムスタンプの相違などによるデータ型の成形が必要な場合や、後方互換性を確保するための処理が必要な場合などです。以下では、分かりやすい例として、GraphQL リゾルバーが呼び出されるたびに投稿にランダムな番号を割り当て、ブログの投稿に対する賛成または反対を操作する AWS Lambda 関数を示しています。

```
'use strict';
const doc = require('dynamodb-doc');
const dynamo = new doc.DynamoDB();

exports.handler = (event, context, callback) => {
    const payload = {
        TableName: 'Posts',
        Limit: 50,
        Select: 'ALL_ATTRIBUTES',
    };

    dynamo.scan(payload, (err, data) => {
        const result = { data: data.Items.map(item =>{
            item.ups = parseInt(Math.random() * (50 - 10) + 10, 10);
            item.downs = parseInt(Math.random() * (20 - 0) + 0, 10);
            return item;
        }) };
        callback(err, result.data);
    });
};
```

これは完全に有効な Lambda 関数であり、GraphQL スキーマの `AllPosts` フィールドにアタッチできるため、すべての結果を返すクエリが、賛成/反対に対するランダムな番号を受け取ります。

## DynamoDB と OpenSearch Service
<a name="ddb-and-es"></a>

一部のアプリケーションでは、DynamoDB に対してミューテーションまたは簡単な検索クエリを実行し、バックグラウンドプロセスでドキュメントを OpenSearch Service に転送する場合があります。その後、`searchPosts` リゾルバーを OpenSearch Service データソースに単純にアタッチし、GraphQL クエリを使用して、(DynamoDB のデータからの) 検索結果を返します。これは、キーワードやあいまいワードによる検索、地理空間検索などの高度な検索処理をアプリケーションに追加する場合に非常に役立ちます。DynamoDB からのデータ転送は、ETL プロセスを使用して、または Lambda を使用した DynamoDB からのストリームを使用して行うことができます。これの完全な例は、 AWS アカウントの米国西部 2 (オレゴン) リージョンで次の AWS CloudFormation スタックを使用して起動できます。

[https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?templateURL=https://s3.us-west-2.amazonaws.com/awsappsync/resources/multipledatasource/appsyncesdbstream.yml](https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?templateURL=https://s3.us-west-2.amazonaws.com/awsappsync/resources/multipledatasource/appsyncesdbstream.yml) 

この例では、スキーマは以下のような DynamoDB リゾルバーを使用して投稿を追加します。

```
mutation add {
    putPost(author:"Nadia"
        title:"My first post"
        content:"This is some test content"
        url:"https://aws.amazon.com/appsync/"
    ){
        id
        title
    }
}
```

これにより、データが DynamoDB に書き込まれます。その後、Lambda を介してデータが Amazon OpenSearch Service に転送されます。ここではすべての投稿がさまざまなフィールドについて検索できます。たとえば、データが Amazon OpenSearch Service にあるため、以下のように空白を含む任意のテキストを使用して、author フィールドまたは content フィールドを検索できます。

```
query searchName{
    searchAuthor(name:"   Nadia   "){
        id
        title
        content
    }
}

query searchContent{
    searchContent(text:"test"){
        id
        title
        content
    }
}
```

データは DynamoDB に直接書き込まれるため、`allPosts{...}` クエリと `singlePost{...}` クエリを使用して、テーブルに対するリストまたは項目の検索処理が効率的に実行できます。このスタックでは、DynamoDB ストリームに対して次のコード例を使用します。

 **注意 :** ここで示しているのは一例にすぎません。

```
var AWS = require('aws-sdk');
var path = require('path');
var stream = require('stream');

var esDomain = {
    endpoint: 'https://opensearch-domain-name.REGION.es.amazonaws.com',
    region: 'REGION',
    index: 'id',
    doctype: 'post'
};

var endpoint = new AWS.Endpoint(esDomain.endpoint)
var creds = new AWS.EnvironmentCredentials('AWS');

function postDocumentToES(doc, context) {
    var req = new AWS.HttpRequest(endpoint);

    req.method = 'POST';
    req.path = '/_bulk';
    req.region = esDomain.region;
    req.body = doc;
    req.headers['presigned-expires'] = false;
    req.headers['Host'] = endpoint.host;

    // Sign the request (Sigv4)
    var signer = new AWS.Signers.V4(req, 'es');
    signer.addAuthorization(creds, new Date());

    // Post document to ES
    var send = new AWS.NodeHttpClient();
    send.handleRequest(req, null, function (httpResp) {
        var body = '';
        httpResp.on('data', function (chunk) {
            body += chunk;
        });
        httpResp.on('end', function (chunk) {
            console.log('Successful', body);
            context.succeed();
        });
    }, function (err) {
        console.log('Error: ' + err);
        context.fail();
    });
}

exports.handler = (event, context, callback) => {
    console.log("event => " + JSON.stringify(event));
    var posts = '';

    for (var i = 0; i < event.Records.length; i++) {
        var eventName = event.Records[i].eventName;
        var actionType = '';
        var image;
        var noDoc = false;
        switch (eventName) {
            case 'INSERT':
                actionType = 'create';
                image = event.Records[i].dynamodb.NewImage;
                break;
            case 'MODIFY':
                actionType = 'update';
                image = event.Records[i].dynamodb.NewImage;
                break;
            case 'REMOVE':
            actionType = 'delete';
                image = event.Records[i].dynamodb.OldImage;
                noDoc = true;
                break;
        }

        if (typeof image !== "undefined") {
            var postData = {};
            for (var key in image) {
                if (image.hasOwnProperty(key)) {
                    if (key === 'postId') {
                        postData['id'] = image[key].S;
                    } else {
                        var val = image[key];
                        if (val.hasOwnProperty('S')) {
                            postData[key] = val.S;
                        } else if (val.hasOwnProperty('N')) {
                            postData[key] = val.N;
                        }
                    }
                }
            }

            var action = {};
            action[actionType] = {};
            action[actionType]._index = 'id';
            action[actionType]._type = 'post';
            action[actionType]._id = postData['id'];
            posts += [
                JSON.stringify(action),
            ].concat(noDoc?[]:[JSON.stringify(postData)]).join('\n') + '\n';
        }
    }
    console.log('posts:',posts);
    postDocumentToES(posts, context);
};
```

DynamoDB ストリームを使用し、`id` のプライマリキーを使用してこれを DynamoDB テーブルにアタッチできます。DynamoDB のソースへの変更は OpenSearch Service ドメインに転送されます。この設定の詳細については、[DynamoDB Streams のドキュメント](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html)を参照してください。