Aws-sdk problems

Hi,

I’m trying to do some PoC work with Forge. I want to be able to click a button on an Issue Panel that invokes a handler that will then make a request to AWS. I have the button and the handler hooked up, but as soon as I try to interact with the aws-sdk I run into problems.

I’ve tried both v2 and v3 and get different problems. I’d be happy with a solution for either, although I’d prefer v3 over v2 if possible.

aws-sdk v3:

import {S3Client, ListBucketsCommand} from '@aws-sdk/client-s3';

const s3 = new S3Client({region: 'eu-west-2', credential: {...}});

This complains that the nested call to new http.Agent() is not a constructor. Localised to:

import http from 'http';

const httpAgent = new http.Agent();

Gives the ‘is not a constructor’ error.

aws-sdk v2:

import S3 from 'aws-sdk/clients/s3';

const s3 = new S3({region: 'eu-west-2', credentials: {...}});
await s3.listBuckets().promise()
    .then((result) => {...})
    .catch((err) => console.log(`Error: ${err}`));

Displays the message: Error: NetworkingError: XMLHttpRequest is not defined

Any advice on how to get either version of the aws-sdk to work in forge would be appreciated. Thanks.

N.B. I won’t see any replies after 5pm GMT today until Wednesday 5th January.

Just briefly based on our early attempts (i.e. I haven’t tried again for a few months), the Forge runtime has significant deviations from and limitations compared to Node.js due to its sandboxing approach. In particular, various built-in modules are not supported, which includes XMLHttpRequest, or only partially implemented like the crypto module.

This makes it difficult to adopt more complex third-party libraries that use such features under the hood, and the AWS SDK for JavaScript is one of those, with v2 looking outright impossible, and v3 still looking difficult and likely requiring a patched version or unsupported polyfilling.

  • Notably the Forge runtime presents itself as a hybrid between a browser and a Node.js environment, which makes this even more difficult due to the AWS SDK for JavaScript forking its behavior and implementation on that very boundary (e.g. for authentication).

After hitting these walls, we quickly backed out and decided to only use AWS features behind our own APIs for the time being (i.e. API Gateway for REST or AppSync for GraphQL). And this has just gotten more flexible thanks to the new Forge external authentication, which also supports Cognito User Pools.


PS: While I’d ultimately love to see Atlassian leveraging the fact that Forge is build atop AWS by surfacing resp. native integrations (with IAM and EventBridge being the most obvious candidates), their decisions and focus so far seemed to indicate that they do not want go that route currently, so we concluded it wouldn’t make sense to engage regarding those comparatively advanced and platform dependent architectural patterns.

2 Likes

Hi spoel,

Thanks. That was pretty much what I was afraid of. We’ve had to re-implement parts of the AWS SDK in other environments for similar reasons. I’d hoped we wouldn’t need to do that again.

I’ll feed this back to my team in the New Year.

Paul

2 Likes

For anyone who stumbles upon this with a similar problem, it is possible to do some limited actions with the AWS SDK by creating a pre-signed URL and then feeding this into forge/api’s version of fetch.

Here’s an example of using this approach to get an object from an S3 bucket:

import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { fetch } from '@forge/api';

const s3Client = new S3Client({
    region: region,
    credentials: {
        accessKeyId: accesskeyid,
        secretAccessKey: secretaccesskey
    }
});
const getCommand = new GetObjectCommand({
    Bucket: bucket,
    Key: objectName
});
const url = await getSignedUrl(s3Client, getCommand, { expiresIn: 120 });
const response = await fetch(url, {
    method: 'GET'
});

Note that you’ll have to turn off snapshots to get the aws-sdk to run when tunnelling as this still throws one of those ‘out of memory’ errors.

3 Likes