web-dev-qa-db-fra.com

Comment télécharger un fichier sur AWS S3 à l'aide de AWS AppSync

Suite à ce document/tutorial dans AWS AppSync Docs.

Il est dit:

Avec AWS AppSync, vous pouvez les modéliser en tant que types GraphQL. Si l'une de vos mutations comporte une variable avec des champs de compartiment, clé, région, mimeType et localUri, le SDK téléchargera le fichier sur Amazon S3 pour vous.

Cependant, je ne peux pas charger mon fichier dans mon compartiment s3. Je comprends que ce tutoriel manque beaucoup de détails. Plus spécifiquement, le tutoriel ne dit pas que le NewPostMutation.js doit être changé.

Je l'ai changé de la manière suivante:

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
    }
}
`

Pourtant, même après avoir implémenté ces modifications, le fichier n'a pas été téléchargé ...

9
SaidAkh

Il y a quelques pièces mobiles sous le capot que vous devez vous assurer d'avoir en place avant que cela "fonctionne". Tout d’abord, vous devez vous assurer que vous disposez d’une entrée et d’un type appropriés pour un objet S3 défini dans votre schéma GraphQL.

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!
}

Bien sûr, le type S3ObjectInput est utilisé lors du téléchargement d'un nouveau fichier, que ce soit pour créer ou mettre à jour un modèle dans lequel les métadonnées de l'objet S3 sont incorporées. Il peut être manipulé dans le résolveur de requête d'une mutation via:

{
    "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)
}

Cela suppose que l'objet de fichier S3 est un champ enfant d'un modèle attaché à une source de données DynamoDB. Notez que l'appel à $utils.dynamodb.toS3Object() configure l'objet S3 complexe file, qui est un champ du modèle avec le type S3ObjectInput. Configurer le résolveur de requêtes de cette manière gère le téléchargement d'un fichier sur S3 (lorsque toutes les informations d'identification sont configurées correctement - nous y reviendrons dans un instant), mais cela n'indique pas comment récupérer le S3Object. C’est là qu’un résolveur de niveau de champ attaché à une source de données locale devient nécessaire. En gros, vous devez créer une source de données locale dans AppSync et la connecter au champ file du modèle dans le schéma à l'aide des résolveurs de demande et de réponse suivants:

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

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

Ce résolveur indique simplement à AppSync que nous voulons utiliser la chaîne JSON stockée dans DynamoDB pour le champ file du modèle et l’analyser dans un S3Object - de cette manière, lorsque vous effectuez une requête du modèle au lieu de renvoyer la chaîne stockée. Dans le champ file, vous obtenez un objet contenant les propriétés bucket, region et key que vous pouvez utiliser pour créer une URL permettant d'accéder à l'objet S3 (directement via S3 ou à l'aide d'un CDN - qui dépend réellement de votre configuration).

Assurez-vous cependant que les informations d'identification sont configurées pour les objets complexes (je vous ai dit que j'y reviendrais). Je vais utiliser un exemple de React pour illustrer cela: lors de la définition de vos paramètres AppSync (noeud final, auth, etc.), il existe une propriété supplémentaire appelée complexObjectCredentials qui doit être définie pour indiquer au client les informations d'identification AWS à utiliser pour gérer les téléchargements S3. , par exemple:

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

En supposant que toutes ces choses soient en place, les téléchargements S3 et via AppSync devraient fonctionner.

16
hatboyzero

Juste pour ajouter à la discussion. Pour les clients mobiles, amplify (ou si vous le faites depuis la console aws) encapsulera les appels de mutation dans un objet. Les clients ne téléchargeront pas automatiquement si l'encapsulation existe. Ainsi, vous pouvez modifier l'appel de mutation directement dans la console aws afin que le fichier de chargement : S3ObjectInput se trouve dans les paramètres d'appel. Cela se passait la dernière fois que j'ai testé (décembre 2018) après la documentation. 

Vous changeriez à cette structure d'appel:

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

Au lieu d'appels générés automatiquement comme:

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

Une fois que vous avez apporté cette modification, iOS et Android téléchargeront volontiers votre contenu si vous faites ce que @hatboyzero a décrit.

[Edit] J'ai fait quelques recherches, ce qui aurait été corrigé dans 2.7.3 https://github.com/awslabs/aws-mobile-appsync-sdk-Android/issues/11 . Ils se sont probablement adressés à iOS mais je n'ai pas vérifié.

0
Bruce