0

I have a Serverless (AWS) application written in NodeJS with exposed GraphQL endpoint and Upload mutation for image upload to S3 bucket.

GraphQL lambda is defined as follows

graphql:
  handler: src/functions/graphql/graphql.handler
  name: ${self:provider.stackName}-graphql
  events:
    - http:
        method: POST
        path: /graphql

GraphQL lambda is basically this

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

export const handler = server.createHandler();

I have an upload mutation defined

type Mutation {
    uploadPhoto(file: Upload!, location: String): String!
}

And resolver looks like this

public async uploadPhoto(
    parent: any,
    params: { file: any; location: string }
  ): Promise<string> {
    const file = await params.file;

    const { createReadStream, filename, mimetype } = file;
    const { ext } = parse(filename);
    const uploadParams: S3.Types.PutObjectRequest = {
      Bucket: process.env.PHOTO_BUCKET,
      Key: `${params.location}/${randomNumber}${ext}`,
      ContentType: mimetype,
      Body: createReadStream(),
      ContentEncoding: "base64",
      ACL: "public-read",
    };
    try {
      console.log("upload params", uploadParams);
      const sendData = await this.s3bucket.upload(uploadParams).promise();
      console.log(sendData);
      return sendData.Location;
    } catch (error) {
      console.log("error uploading file", error);
      return error.message;
    }
  }

Also to enable API Gateway to accept binary data I've installed

custom:
  apigwBinary:
    types: 
      - image/jpeg
      - image/jpg
      - image/png

plugins:
  - serverless-apigw-binary

Still, after all this, I can upload .txt files for instance, but images just look something like this https://cutt.ly/cg7zA6O so like an empty file. Content-type is ok, file size is also ok, but the image is corrupted.

My guess would be something about API Gateway is wrong, but I'm not 100% sure

Vuk Stanković
  • 7,864
  • 10
  • 41
  • 65
  • Does your read stream actually produce base64-encoded data? – jarmod Nov 17 '20 at 14:33
  • @jarmod it's producing a Buffer and when I read a stream to buffer and do `buffer.toString("base64")` I get a string looking something like this ``` /VBORw0KGgoAAAANSUhEUgAAA1wAAAL9CAYAAAD9Iv39AAB4aUlEQVR4/f39W/01/f1g/RpMT1FAT/1HUkD9Qx39PEn9/f0X/f07PwMWSiX9H/39X/1oRv1//f1//f39AgAAAAD9/V8OAgAAAAAQLgAAAAAgXAAAAAAA/QUAAAAA... ``` When I try to parse this as image I get an error that it's not an image but `image/octet-stream` – Vuk Stanković Nov 17 '20 at 14:46
  • It's actually a binary buffer cc @jarmod – Vuk Stanković Nov 17 '20 at 15:31
  • You typically don't need to encode. Create a regular ReadableStream on a file and provide that stream to the upload function, if possible. – jarmod Nov 17 '20 at 15:35
  • That is what I tried here by doing `Body: createReadStream()`, but I can't get it to work. Also, this works for .txt for instance, but not for images – Vuk Stanković Nov 17 '20 at 16:08
  • @VukStanković did you resolve this issue? if so, how? – praveen kumar Jul 28 '21 at 14:46
  • Honestly, it just started working, but I didn't use this implementation at all in the end. I've used signed URLs to upload files – Vuk Stanković Aug 08 '21 at 08:47

0 Answers0