Skip to content

Adds koa route #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -98,9 +98,11 @@ function getSignedUrl(file, callback) {

Server-Side
-----------
### Bundled router
### Bundled routers
You can use the Express router that is bundled with this module to answer calls to `/s3/sign`

#### Express

```js
app.use('/s3', require('react-s3-uploader/s3router')({
bucket: "MyS3Bucket",
@@ -111,7 +113,19 @@ app.use('/s3', require('react-s3-uploader/s3router')({
}));
```

This also provides another endpoint: `GET /s3/img/(.*)` and `GET /s3/uploads/(.*)`. This will create a temporary URL
# Koa 1.0

```js
import s3router from 'react-s3-uploader/s3router';

app.use(require('react-s3-uploader/s3router')({
/* Same as above with these additional options: */
endpoint: 'https://rest.s3alternative.com', // optional. useful for s3-compatible APIs
prefix: '/v1/s3' // optional. default is /s3. useful if you version your API endpoints
}));
```

These also provide another endpoint: `GET /s3/img/(.*)` and `GET /s3/uploads/(.*)`. This will create a temporary URL
that provides access to the uploaded file (which are uploaded privately by default). The
request is then redirected to the URL, so that the image is served to the client.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -25,9 +25,10 @@
"homepage": "https://github.com/odysseyscience/react-s3-uploader",
"dependencies": {
"aws-sdk": "2.x",
"koa-router": "^5.4.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im not familiar with koa, but notice we took out the express dependency in this file, and are just relying on people have it installed if they are using the bundled router. That keeps it so that people not using express (or in this case koa) don't have to download the dependency.

Is koa a large library? Does it have a lot of dependencies? If so, we should probably remove it from this file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Koa would need to be in the server.js (presumably) already to work. You'll do

const app = koa()

app.use(s3routes(options))

No real way to not already have koa.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are using this router, the assumption would be that you already have a dependency on koa. But if you aren't using this router, you don't want the koa dependency, and you would get it if this line exists in package.json. So we should delete this line from here I think. Make sense?

"latinize": "0.2.x",
"node-uuid": "1.x",
"object-assign": "^2.0.0",
"latinize": "0.2.x",
"unorm": "1.4.x"
},
"peerDependencies": {
111 changes: 111 additions & 0 deletions s3router-koa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import Router from 'koa-router';
import uuid from 'node-uuid';
import AWS from 'aws-sdk';

const { S3_ACCESS_KEY, S3_SECRET_ACCESS_KEY, S3_ENDPOINT } = process.env;

function checkTrailingSlash (path) {
let newPath;

if (path && path[path.length - 1] !== '/') {
newPath = path + '/';
}

return newPath;
}

export default function S3Router (options) {
const S3_BUCKET = options.bucket;

if (!S3_BUCKET) {
throw new Error('S3_BUCKET is required.');
}

const s3Options = {};
if (options.region) {
s3Options.region = options.region;
}
if (options.signatureVersion) {
s3Options.signatureVersion = options.signatureVersion;
}
if (options.endpoint) {
s3Options.endpoint = options.endpoint;
}

const s3 = new AWS.S3({
...s3Options,
accessKeyId: S3_ACCESS_KEY,
secretAccessKey: S3_SECRET_ACCESS_KEY,
endpoint: S3_ENDPOINT
});

const router = new Router({
prefix: options.prefix || 's3'
});

/**
* Redirects image requests with a temporary signed URL, giving access
* to GET an upload.
*/
function * tempRedirect() {
const self = this;

const params = {
Bucket: S3_BUCKET,
Key: options.key
};

s3.getSignedUrl('getObject', params, function (err, url) {
self.redirect(url);
});
}

/**
* Image specific route.
*/
router.get(/\/img\/(.*)/, tempRedirect);

/**
* Other file type(s) route.
*/
router.get(/\/uploads\/(.*)/, tempRedirect);

/**
* Returns an object with `signedUrl` and `publicUrl` properties that
* give temporary access to PUT an object in an S3 bucket.
*/
router.get('/sign', function * () {
const self = this;
const filename = uuid.v4() + '_' + this.query.objectName;
const mimeType = this.query.contentType;

// Set any custom headers
if (options.headers) {
this.set(options.headers);
}

const params = {
Bucket: S3_BUCKET,
Key: checkTrailingSlash(options.key) + filename,
Expires: 60,
ContentType: mimeType,
ACL: options.ACL || 'private'
};

s3.getSignedUrl('putObject', params, function (err, data) {
if (err) {
console.log(err);
self.status = 500;
self.body = 'Cannot create S3 signed URL';
}

self.body = {
signedUrl: data,
publicUrl: '/s3/uploads/' + filename,
filename
};
});
});

return router.routes();
}
Copy link
Contributor

@seanadkinson seanadkinson Aug 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first glance, this file looks just the same as the bundled router, except for the unused generator annotations on the methods. Can you let me know what this file does differently to support koa, and why the existing router doesn't work?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At second glance, it is quite a bit different. You are using ES6/7 things here, which we didn't do in s3router because we didn't want to require babel for people. Does koa automatically support ES6/7?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe Koa requires ES6/7 because it uses generators, which are an ES6 feature. So anyone using Koa will be using that. However, I should probably remove the imports too be save because even some ES6/Koa people are not guaranteed to use that.