Skip to content

Instantly share code, notes, and snippets.

@phuochau
Last active October 18, 2022 11:09
Show Gist options
  • Save phuochau/977d9d9aa66a70b7577f1b9848d2e38d to your computer and use it in GitHub Desktop.
Save phuochau/977d9d9aa66a70b7577f1b9848d2e38d to your computer and use it in GitHub Desktop.
Generate Signed URL by NodeJS

Configure Amazon S3, generate signed url by NodeJS and upload in React Native

1. Configure Amazon S3 (updating...)

2. Generate signed url by NodeJS

import AWS from 'aws-sdk'
import { getFileType } from './File'

const s3 = new AWS.S3({
  accessKeyId: process.env.AWS_S3_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_S3_SECRET_ACCESS_KEY,
  useAccelerateEndpoint: process.env.ENV === 'prod',
  region: process.env.AWS_S3_REGION
})

const getFileUrl = (key) => {
  return `http://${process.env.AWS_S3_BUCKET_NAME}.s3-${process.env.AWS_S3_REGION}.amazonaws.com/${key}`
}

export const getS3PresignedUrl = (key, expireSeconds = 60 * 60, ACL = 'public-read') => {
  if (!key) return Promise.resolve(null)

  const fileType = getFileType(key)
  const params = {
    Bucket: process.env.AWS_S3_BUCKET_NAME,
    Key: key,
    Expires: expireSeconds,
    ACL,
    ContentType: fileType
  }

  return new Promise((resolve, reject) => {
    s3.getSignedUrl('putObject', params, (err, url) => {
      if (err) return reject(err)
      resolve({
        signedUrl: url,
        contentType: fileType,
        fileUrl: getFileUrl(envKey)
      })
    })
  })
}

3. Use in React Native:

import { mutate, GraphQLResponse } from '../helpers'
import { FetchBlobResponse } from 'rn-fetch-blob';

export const putFileToS3 = (s3Url: string, uri: string, contentType: string) => {
  if (!s3Url || !uri) return Promise.reject(new Error('Empty data'))

  return RNFetchBlob.fetch('PUT', s3Url, {
    'Content-Type': contentType
  }, RNFetchBlob.wrap(uri.replace('file://', '')))
}

export const getUploadSignedUrl = (params: object = {}) : Promise<GraphQLResponse> => {
  return mutate(MutationGetUploadSignedUrl, params)
}

export const uploadFile = async (uri: string, onUploadProgress?: (props: object) => any) : Promise<GraphQLResponse> => {
  if (!uri) return Promise.resolve({ success: false, data: 'file_empty' })
  const filename = getFilename(uri)
  if (!filename) return Promise.resolve({ success: false, data: 'file_name_cant_parse' })

  const { success, data } = await getUploadSignedUrl({ filename })
  if (!success || !data) return Promise.resolve({ success: false, data })

  const { contentType, signedUrl, fileUrl } = data.getUploadSignedUrl

  return new Promise((resolve, reject) => {
    putFileToS3(signedUrl, uri, contentType)
      .uploadProgress((written: number, total: number) => {
        if (onUploadProgress) {
          onUploadProgress({
            written,
            total,
            percent: Math.floor((written/total) * 100)
          })
        }
      }).then((res: FetchBlobResponse) => {
        const status = res.respInfo.status
        if (status === 200) return resolve({ success: true, data: fileUrl })
        resolve({ success: false })
      }).catch((e: any) => {
        resolve({ success: false, data: e })
      })
  })
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment