Navigation

Amazon S3 JavaScript Tutorial

Amazon S3 is a component of Amazon Web Services that provides a simple key-value store useful for storing and serving static resources. This tutorial will walk through the components of a simple JavaScript application using MongoDB Stitch with Amazon S3.

To follow this tutorial, you need:

  • A MongoDB Stitch app with anonymous authentication enabled,
  • At least one globally-readable S3 bucket in the US Standard (US East) region, and
  • An Amazon AWS user with PutObject permission on that bucket and an access key pair.

A Public Whiteboard Application

In this tutorial, you will create a website where anonymous users may view and replace a shared text message stored on Amazon S3.

1

Configure CORS

A JavaScript application cannot make a cross-domain request to a resource lacking a CORS (Cross-Origin Resource Sharing) configuration.

Ensure that your bucket has a CORS configuration that permits HTTP GET requests from any origin, such as the following:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Refer to Amazon’s documentation on Cross-Origin Resource Sharing for details on how to configure your bucket.

2

Add an S3 service.

You must create an Amazon S3 service in your MongoDB Stitch application.

  1. Click the ADD SERVICE button in the left-side navigation pane.

  2. Select the S3 box. In the Service Name box at the bottom, enter Whiteboard.

  3. Click Add service.

  4. Enter the Amazon Region on which you deployed your bucket (the US Standard region is us-east-1), along with an Amazon Access Key ID and Secret Access Key.

  5. Select the Rules tab, and click ADD RULE.

  6. Check the put checkbox, and enter the following into the When text box:

    {
      "bucket": "<your-bucket>"
    }
    

    This will only allow put actions to be executed against your bucket.

  7. Click SAVE.

3

Initialize the Client and Log In as an Anonymous User

Instantiate a new stitch.StitchClient instance with your MongoDB Stitch application ID, and authenticate as an anonymous user:

const stitchClient = new stitch.StitchClient('<your-app-id>');
const promise = stitchClient.login();
4

PUT an Object

Use the binary action to decode Base64-encoded data into a binary stream, and feed this binary stream into the MongoDB Stitch put action to save an object into your S3 bucket:

function upload(text) {
    return stitchClient.executePipeline([{
       action: "binary",
       args: {
            "encoding": "base64",
            "data": btoa(text)
        }
    },
    {
       service: "Whiteboard",
       action: "put",
       args: {
            "bucket": bucket,
            "key": objectKey,
            "acl": "public-read",
            "contentType": "text/plain"
        }
    }]);
}

Complete Example

Substitute <your-bucket> with the name of your S3 bucket, and <your-app-id> with your MongoDB Stitch application ID.

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<!doctype html>
<html>
    <head>
        <title>S3 Whiteboard</title>
        <meta charset="utf-8">
    </head>
    <body>
        <script defer type="text/javascript" src="https://s3.amazonaws.com/stitch-sdks/js/library/stable/stitch.min.js"></script>
        <script defer type="text/javascript" src="app.js"></script>

        <textarea id="input-text" cols="80" rows="10"></textarea>
        <button id ="button-submit">Submit</button>
        <button id ="button-refresh">Refresh</button>
    </body>
</html>

app.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
document.addEventListener('DOMContentLoaded', () => {
    'use strict';
    const textArea = document.getElementById('input-text');
    const submitButton = document.getElementById('button-submit');
    const refreshButton = document.getElementById('button-refresh');

    const bucket = '<your-bucket>';
    const objectKey = 'shared-text';
    const stitchClient = new stitch.StitchClient('<your-app-id>');

    function upload(text) {
        return stitchClient.executePipeline([{
           action: "binary",
           args: {
                "encoding": "base64",
                "data": btoa(text)
            }
        },
        {
           service: "Whiteboard",
           action: "put",
           args: {
                "bucket": bucket,
                "key": objectKey,
                "acl": "public-read",
                "contentType": "text/plain"
            }
        }]);
    }

    function refresh() {
        const xhr = new XMLHttpRequest();
        const url = `https://${bucket}.s3.amazonaws.com/${encodeURIComponent(objectKey)}?${new Date().getTime()}`;
        return new Promise((resolve, reject) => {
            xhr.onload = function() {
                if (xhr.status >= 200 && xhr.status < 400) {
                    resolve(xhr.responseText);
                } else if (xhr.status === 404) {
                    resolve('');
                } else {
                    reject();
                }
            };

            xhr.onerror = function() { reject(); };

            xhr.open('GET', url, true);
            try {
                xhr.send();
            } catch (err) {
                reject(err);
            }
        }).then((text) => {
            textArea.value = text;
            console.log('Done');
        }).catch((err) => {
            console.error('Error', err);
        });
    }

    const promise = stitchClient.login();
    promise.then(() => {
        console.log('Authenticated');

        submitButton.onclick = () => {
            upload(textArea.value).then(() => {
                console.log('Submitted');
            }).catch((err) => {
                console.error('Error while submitting', err)
            });
        };

        refreshButton.onclick = () => {
            refresh().then(() => {
                console.log('Refreshed');
            }).catch((err) => {
                console.error('Error while submitting', err)
            });
        };

        refresh();
    });
});