web-dev-qa-db-ja.com

AWS AppSyncを使用してAWS S3にファイルをアップロードする方法

AWS AppSyncドキュメントの this docs/tutorial に従います。

状態:

AWS AppSyncを使用すると、これらをGraphQLタイプとしてモデル化できます。いずれかのミューテーションにバケット、キー、リージョン、mimeType、およびlocalUriフィールドを持つ変数がある場合、SDKはファイルをAmazon S3にアップロードします。

ただし、s3バケットにアップロードするファイルを作成できません。そのチュートリアルには多くの詳細が欠けていることを理解しています。より具体的には、チュートリアルではNewPostMutation.jsを変更する必要があります。

次のように変更しました。

import gql from 'graphql-tag';

export default gql`
mutation AddPostMutation($author: String!, $title: String!, $url: String!, $content: String!, $file: S3ObjectInput ) {
    addPost(
        author: $author
        title: $title
        url: $url
        content: $content
        file: $file
    ){
        __typename
        id
        author
        title
        url
        content
        version
    }
}
`

それでも、これらの変更を実装した後でも、ファイルはアップロードされませんでした...

18
SaidAkh

この「ジャスト・ワークス」(TM)の前に所定の位置にあることを確認する必要があるボンネットの下に、いくつかの可動部品があります。まず、GraphQLスキーマで定義されたS3オブジェクトの適切な入力とタイプを確認する必要があります

_enum Visibility {
    public
    private
}

input S3ObjectInput {
    bucket: String!
    region: String!
    localUri: String
    visibility: Visibility
    key: String
    mimeType: String
}

type S3Object {
    bucket: String!
    region: String!
    key: String!
}
_

もちろん、_S3ObjectInput_タイプは、新しいファイルをアップロードするときに使用します-S3オブジェクトメタデータが埋め込まれているモデルを作成または更新する方法のいずれかを使用して。次の方法で、ミューテーションのリクエストリゾルバで処理できます。

_{
    "version": "2017-02-28",
    "operation": "PutItem",
    "key": {
        "id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id),
    },

    #set( $attribs = $util.dynamodb.toMapValues($ctx.args.input) )
    #set( $file = $ctx.args.input.file )
    #set( $attribs.file = $util.dynamodb.toS3Object($file.key, $file.bucket, $file.region, $file.version) )

    "attributeValues": $util.toJson($attribs)
}
_

これは、S3ファイルオブジェクトがDynamoDBデータソースにアタッチされたモデルの子フィールドであると仮定しています。 $utils.dynamodb.toS3Object()を呼び出すと、_S3ObjectInput_型のモデルのフィールドである複雑なS3オブジェクトfileが設定されます。この方法でリクエストリゾルバーを設定すると、S3へのファイルのアップロードが処理されます(すべての資格情報が正しく設定されたら-すぐに触れます)が、_S3Object_戻る。これは、ローカルデータソースに接続されたフィールドレベルリゾルバが必要になる場所です。本質的に、AppSyncでローカルデータソースを作成し、次のリクエストおよびレスポンスリゾルバを使用してスキーマのモデルのfileフィールドに接続する必要があります。

_## Request Resolver ##
{
    "version": "2017-02-28",
    "payload": {}
}

## Response Resolver ##
$util.toJson($util.dynamodb.fromS3ObjectJson($context.source.file))
_

このリゾルバーは、モデルのfileフィールドに対してDynamoDBに保存されているJSON文字列を取得し、それを_S3Object_に解析することをAppSyncに伝えるだけです。モデルは、fileフィールドに格納されている文字列を返す代わりに、bucketregion、およびkeyプロパティを含むオブジェクトを取得できます。 S3オブジェクトにアクセスするためのURLを作成するために使用します(S3を介して直接、またはCDNを使用して-これは実際に構成に依存します)。

ただし、複雑なオブジェクトの資格情報が設定されていることを確認してください(これについては後で説明します)。これを説明するためにReactの例を使用します-AppSyncパラメーター(エンドポイント、認証など)を定義するとき、必要なcomplexObjectCredentialsという追加のプロパティがありますS3アップロードの処理に使用するAWS認証情報をクライアントに伝えるように定義されています。例:

_const client = new AWSAppSyncClient({
    url: AppSync.graphqlEndpoint,
    region: AppSync.region,
    auth: {
        type: AUTH_TYPE.AWS_IAM,
        credentials: () => Auth.currentCredentials()
    },
    complexObjectsCredentials: () => Auth.currentCredentials(),
});
_

これらすべてが整っていると仮定すると、AppSyncを介したS3のアップロードとダウンロードが機能するはずです。

21
hatboyzero

ディスカッションに追加するだけです。モバイルクライアントの場合、amplify(またはAWSコンソールから行う場合)は、変異呼び出しをオブジェクトにカプセル化します。カプセル化が存在する場合、クライアントは自動アップロードしません。そのため、awsコンソールでミューテーションコールを直接変更して、アップロードfile:S3ObjectInputが呼び出しパラメーターに含まれるようにすることができます。これは、ドキュメントに従って前回テストしたとき(2018年12月)に発生していました。

この呼び出し構造に変更します。

 type Mutation {
        createRoom(
        id: ID!,
        name: String!,
        file: S3ObjectInput,
        roomTourId: ID
    ): Room
}

次のような自動生成された呼び出しの代わりに:

type Mutation {
    createRoom(input: CreateRoomInput!): Room
}
input CreateRoomInput {
    id: ID
    name: String!
    file: S3ObjectInput
}

この変更を行うと、iOSとAndroidの両方が、@ hatboyzeroが概説したことを行うとコンテンツを喜んでアップロードします。

[編集]少し調べたところ、おそらく2.7.3で修正されたと思われます https://github.com/awslabs/aws-mobile-appsync-sdk-Android/issues/11 。彼らはおそらくiOSに対処しましたが、私はチェックしませんでした。

1
Bruce