如何使用 GraphQL 将图像上传到 AWS S3? [英] How to upload an image to AWS S3 using GraphQL?

查看:32
本文介绍了如何使用 GraphQL 将图像上传到 AWS S3?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在上传 base64 字符串,但 GraphQL 挂起.如果我将字符串切片到少于 50,000 个字符,它就可以工作.在 50,000 个字符之后,graphQL 永远不会进入解析函数,但也不会给出错误.在较小的字符串上,它工作得很好.

I'm uploading a base64 string but the GraphQL gets hung. If I slice the string to less than 50,000 characters it works. After 50,000 characters, graphQL never makes it to the resolve function, yet does not give an error. On the smaller strings, it works just fine.

const file = e.target.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
  const imageArray = reader.result;
  this.context.fetch('/graphql', {
    body: JSON.stringify({
      query: `mutation s3Upload($img: String!) {
        s3Upload(file: $img) {
          logo,
        }
      }`,
      variables: {
        img: imageArray,
      },
    }),
  }).then(response => response.json())
  .then(({ data }) => {
    console.log(data);
  });
}

const s3Upload = {
    type: S3Type,
    args: {
      file: { type: new NonNull(StringType) },
    },
    resolve: (root, args, { user }) => upload(root, args, user),
};

const S3Type = new ObjectType({
  name: 'S3',
  fields: {
    logo: { type: StringType },
  },
});

推荐答案

此处的正确方法是使用 AWS AppSync 通过复杂类型执行实际的 S3 上传 - 您在此处说明的内容看起来更像是您正在尝试保存 base64将图像编码为一个字段的字符串,我只能假设它是一个 DynamoDB 表条目.但是,要使其正常工作,您需要修改您的变更,使 file 字段不是 String!,而是 S3ObjectInput.

The correct approach here is to perform an actual S3 upload via a complex type using AWS AppSync - what you illustrate here looks more like you are attempting to save a base64 encoded image as a string to a field in what I can only assume to be a DynamoDB table entry. For this to work, though, you need to modify your mutation such that the file field is not a String!, but an S3ObjectInput.

引擎盖下有一些活动部件,您需要确保在此正常工作"(TM) 之前已安装到位.首先,您需要确保您的 GraphQL 架构中定义的 S3 对象具有适当的输入和类型

There's a few moving parts under the hood you need to make sure you have in place before this "just works" (TM). First of all, you need to make sure you have an appropriate input and type for an S3 object defined in your GraphQL schema

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 对象元数据的模型.它可以通过以下方式在突变的请求解析器中处理:

The S3ObjectInput type, of course, is for use when uploading a new file - either by way of creating or updating a model within which said S3 object metadata is embedded. It can be handled in the request resolver of a mutation via the following:

{
    "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() 的调用设置了复杂的 S3 对象 file,它是具有 S3ObjectInput 类型的模型字段.以这种方式设置请求解析器可以处理将文件上传到 S3(当所有凭据都设置正确时 - 我们稍后会谈到),但它没有解决如何获取 S3Object 返回.这是附加到本地数据源的字段级解析器变得必要的地方.本质上,您需要在 AppSync 中创建一个本地数据源,并使用以下请求和响应解析器将其连接到模式中模型的 file 字段:

This is making the assumption that the S3 file object is a child field of a model attached to a DynamoDB datasource. Note that the call to $utils.dynamodb.toS3Object() sets up the complex S3 object file, which is a field of the model with a type of S3ObjectInput. Setting up the request resolver in this way handles the upload of a file to S3 (when all the credentials are set up correctly - we'll touch on that in a moment), but it doesn't address how to get the S3Object back. This is where a field level resolver attached to a local datasource becomes necessary. In essence, you need to create a local datasource in AppSync and connect it to the model's file field in the schema with the following request and response resolvers:

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

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

这个解析器只是告诉 AppSync 我们想要为模型的 file 字段获取存储在 DynamoDB 中的 JSON 字符串,并将其解析为 S3Object - 这这样,当您查询模型时,您会得到一个包含 bucketregionfile 字段中的字符串code> 和 key 属性,您可以使用它们来构建 URL 以访问 S3 对象(直接通过 S3 或使用 CDN - 这实际上取决于您的配置).

This resolver simply tells AppSync that we want to take the JSON string that is stored in DynamoDB for the file field of the model and parse it into an S3Object - this way, when you do a query of the model, instead of returning the string stored in the file field, you get an object containing the bucket, region, and key properties that you can use to build a URL to access the S3 Object (either directly via S3 or using a CDN - that's really dependent on your configuration).

请确保您已为复杂对象设置了凭据(我告诉过您我会回到这个问题).我将使用一个 React 示例来说明这一点 - 在定义您的 AppSync 参数(端点、身份验证等)时,需要定义一个名为 complexObjectCredentials 的附加属性来告诉客户端什么 AWS用于处理 S3 上传的凭据,例如:

Do make sure you have credentials set up for complex objects, however (told you I'd get back to this). I'll use a React example to illustrate this - when defining your AppSync parameters (endpoint, auth, etc.), there is an additional property called complexObjectCredentials that needs to be defined to tell the client what AWS credentials to use to handle S3 uploads, e.g.:

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

假设所有这些都准备就绪,S3 通过 AppSync 上传和下载应该可以工作.

Assuming all of these things are in place, S3 uploads and downloads via AppSync should work.

这篇关于如何使用 GraphQL 将图像上传到 AWS S3?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆