

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 에서 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>

다음 스키마에는 `Post` 작업 3개와 `Query` 작업 3개가 정의된 `Mutation` 유형이 있습니다.

```
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개 해석기를 연결하게 됩니다. 한 가지 가능한 방법은 [DynamoDB 해석기 매핑 템플릿 참조](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb)에 설명된 대로 이 모든 것을 `Posts`라고 하는 Amazon DynamoDB 테이블에서 가져와서 `AllPosts`가 스캔을 실행하고 `searchPosts`가 쿼리를 실행하도록 하는 것입니다. 하지만 Lambda 또는 OpenSearch Service를 통해 이러한 GraphQL 쿼리를 해석하는 등 사용자의 비즈니스 요구에 맞는 다른 방법도 있습니다.

## 해석기를 통해 데이터 변경
<a name="alter-data-through-resolvers"></a>

DynamoDB(또는 Amazon Aurora) 같은 데이터베이스의 결과를 클라이언트로 반환할 때 몇 가지 속성을 변경한 상태로 반환해야 할 수도 있습니다. 클라이언트의 타임스탬프 차이 같은 데이터 형식의 포맷팅이나 이전 버전과의 호환성 문제를 처리하기 위한 것이 이유일 수 있습니다. 설명을 돕기 위해, 다음 예제에서 AWS Lambda 함수는 GraphQL 해석기가 호출될 때마다 난수를 할당하여 블로그 게시물에 대한 좋아요/싫어요 평가를 다룹니다.

```
'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에 있으므로 다음과 같이 공백으로만 이루어졌더라도 자유 형식의 텍스트를 사용하여 작성자나 콘텐츠 필드를 검색할 수 있습니다.

```
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 테이블에 이 부분을 연결하면, 원본에 대한 모든 변경 내용이 OpenSearch Service 도메인으로 스트리밍됩니다. 이 구성에 대한 자세한 내용은 [DynamoDB Streams 설명서](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html)를 참조하십시오.