How to upload JSON data to AWS S3 with NodeJS AWS SDK and Typescript
Tags: typescript, aws, node, javascript
Published: 2019-09-28 08:54:14

After much Googling and finding [Upload to S3 with Node - The Right Way](https://coolaj86.com/articles/upload-to-s3-with-node-the-right-way/) via [How to upload files to AWS S3 with NodeJS SDK](https://gist.github.com/homam/8646090), then adapting it for my Typescript project, here is another contribution to the topic.

## Code Test With

- Node.js v10.16.3
- Typescript 3.6.3
- AWS SDK 2.525.0

## Assumptions

The code snippet assumes that:

- You are familiar with AWS S3, how it works, how to confirm your uploaded file exists.
- You are able to inject your AWS credentials via environment variables.
- You are okay with an object-oriented solution; although it shouldn't be too hard to convert it to a simple function.

## The Code

The solution is split into two parts, a general client abstraction class to put our convenience methods, and a usage example.

### S3Client

Below is a sample `S3Client` class that I would usually put in a project's `lib/` folder.

There are three main parts:

1. The constructor, which accepts your AWS credentials. 
1. The `put` method is a wrapper that makes AWS' `putObject` callback function that is also `await` ready.
1. The `createPutPublicJsonRequest` is a convenience function with sane defaults that *relevant for my project*, but should probably be changed for your own.

`aws-s3-client.ts`

```typescript
import AWS from 'aws-sdk'

export class S3Client {
  protected client: AWS.S3

  constructor(
    accessKeyId: string,
    secretAccessKey: string
  ) {
    this.client = new AWS.S3({
      accessKeyId,
      secretAccessKey
    })
  }

  public async put(
    request: AWS.S3.Types.PutObjectRequest
  ): Promise<AWS.S3.Types.PutObjectOutput> {
    return new Promise((resolve, reject) => {
      this.client.putObject(request, (error, data) => {
        if (error) {
          return reject(error)
        }

        return resolve(data)
      })
    })
  }

  public createPutPublicJsonRequest(
    location: string,
    filename: string,
    contents: string
  ) {
    const request: AWS.S3.Types.PutObjectRequest = {
      Bucket: location,
      Key: filename,
      Body: contents,
      ContentType: 'application/json; charset=utf-8',
      ACL: 'public-read',
      CacheControl: 'max-age=60'
    }

    return request;
  }
}

```

### Sample Code

To use the class, see below. The returned `s3Response` object will contain an `Etag` that allows you to get more details about it.

`index.ts`

```typescript
import { S3Client } from './lib/aws-s3-client.ts'

const s3Client = new S3Client(
  process.env.ACCESS_KEY_ID,
  process.env.SECRET_ACCESS_KEY
)

const s3PutRequest = s3Client.createPutPublicJsonRequest(
  'mybucket/bucketpath',
  'filename.json',
  JSON.stringify({ hello: 'world' })
)

const s3Response = await s3Client.put(s3PutRequest)
```

## Additional Information

Hopefully the above is a simple starting point for uploading JSON data for public consumption. For more information, check the [official AWS S3 JS SDK API](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html).