aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.39k stars 2.11k forks source link

Cannot call REST api from web worker using aws-ampliy #12860

Open alex-breen opened 5 months ago

alex-breen commented 5 months ago

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

REST API

Amplify Version

v6

Amplify Categories

api

Backend

Amplify CLI

Environment information

``` # Put output below this line System: OS: Windows 11 10.0.22621 CPU: (6) x64 Intel(R) Core(TM) i5-9600K CPU @ 3.70GHz Memory: 3.06 GB / 15.94 GB Binaries: Node: 18.18.0 - C:\Program Files\nodejs\node.EXE npm: 10.1.0 - C:\Program Files\nodejs\npm.CMD Browsers: Chrome: 120.0.6099.217 Edge: Chromium (120.0.2210.133) Internet Explorer: 11.0.22621.1 npmPackages: @aws-amplify/ui-react: ^6.1.1 => 6.1.1 @aws-amplify/ui-react-internal: undefined () @aws-amplify/ui-react-storage: ^3.0.10 => 3.0.10 @types/react: ^18.2.43 => 18.2.47 @types/react-dom: ^18.2.17 => 18.2.18 @vitejs/plugin-react: ^4.2.1 => 4.2.1 aws-amplify: ^6.0.12 => 6.0.12 aws-amplify/adapter-core: undefined () aws-amplify/analytics: undefined () aws-amplify/analytics/kinesis: undefined () aws-amplify/analytics/kinesis-firehose: undefined () aws-amplify/analytics/personalize: undefined () aws-amplify/analytics/pinpoint: undefined () aws-amplify/api: undefined () aws-amplify/api/server: undefined () aws-amplify/auth: undefined () aws-amplify/auth/cognito: undefined () aws-amplify/auth/cognito/server: undefined () aws-amplify/auth/enable-oauth-listener: undefined () aws-amplify/auth/server: undefined () aws-amplify/datastore: undefined () aws-amplify/in-app-messaging: undefined () aws-amplify/in-app-messaging/pinpoint: undefined () aws-amplify/push-notifications: undefined () aws-amplify/push-notifications/pinpoint: undefined () aws-amplify/storage: undefined () aws-amplify/storage/s3: undefined () aws-amplify/storage/s3/server: undefined () aws-amplify/storage/server: undefined () aws-amplify/utils: undefined () eslint: ^8.55.0 => 8.56.0 eslint-plugin-react: ^7.33.2 => 7.33.2 eslint-plugin-react-hooks: ^4.6.0 => 4.6.0 eslint-plugin-react-refresh: ^0.4.5 => 0.4.5 react: ^18.2.0 => 18.2.0 react-dom: ^18.2.0 => 18.2.0 vite: ^5.0.8 => 5.0.11 npmGlobalPackages: @forge/cli: 4.1.1 atlas-connect: 0.8.1 firebase-tools: 10.7.0 mongodb-realm-cli: 2.4.2 npm-check-updates: 12.5.9 npm: 10.1.0 serve: 14.2.1 ```

Describe the bug

From a web worker (on Chrome), invoking a get request to Amplify REST API fails with the following error. GET call failed: InvalidApiName: API name is invalid.

The same request running in the main thread is successful.

Expected behavior

Works the same as when invoked in the main thread.

Reproduction steps

Please see code in snippet below.

Code Snippet

// Put your code below this line.
// WEB WORKER CODE (FAILS)
/* eslint-disable no-restricted-globals */
import { get } from "aws-amplify/api";
console.log("Worker started");

async function getFcn() {
    try {
        const restOperation = get({
            apiName: 'sandbox1',
            path: '/sandbox1'
        });
        const response = await restOperation.response;
        console.log('GET call succeeded: ', response);
    } catch (error) {
        console.log('GET call failed: ', error);
    }
}
getFcn();

// MAIN THREAD CODE (WORKS - see get request within useEffect)
import '@aws-amplify/ui-react/styles.css';
import { get } from 'aws-amplify/api';
import { useEffect, useMemo } from 'react';

const Page = () => {
    const myWorker = useMemo(() => {
        return new Worker(new URL("./worker1.js", import.meta.url), {
            type: "module"
        })
    }, [])

    myWorker.postMessage('Hi worker')
    myWorker.onmessage = function (e) {
        console.log('Message received from worker', e);
    }

    useEffect(() => {
        async function getFcn() {
            try {
                const restOperation = get({
                    apiName: 'sandbox1',
                    path: '/sandbox1'
                });
                const response = await restOperation.response;
                console.log('GET call succeeded: ', response);
            } catch (error) {
                console.log('GET call failed: ', error);
            }
        }
        getFcn();
    }, []);

    return (
        <div>
            Hello again
        </div>
    )
};

export default Page;

Log output

Browser console log below. (Note, no network log as I don't think an attempt to make the call is made.) ``` // Put your logs below this line GET call failed: InvalidApiName: API name is invalid. at assertValidationError (http://localhost:3000/node_modules/.vite/deps/aws-amplify_api.js?v=77a22174:7280:11) at resolveApiUrl (http://localhost:3000/node_modules/.vite/deps/aws-amplify_api.js?v=77a22174:7288:3) at http://localhost:3000/node_modules/.vite/deps/aws-amplify_api.js?v=77a22174:7381:15 at job (http://localhost:3000/node_modules/.vite/deps/aws-amplify_api.js?v=77a22174:7211:69) at createCancellableOperation (http://localhost:3000/node_modules/.vite/deps/aws-amplify_api.js?v=77a22174:7243:24) at publicHandler (http://localhost:3000/node_modules/.vite/deps/aws-amplify_api.js?v=77a22174:7378:51) at get3 (http://localhost:3000/node_modules/.vite/deps/aws-amplify_api.js?v=77a22174:7404:32) at get4 (http://localhost:3000/node_modules/.vite/deps/aws-amplify_api.js?v=77a22174:7412:23) at getFcn (http://localhost:3000/src/worker1.js?type=module&worker_file:8:31) at http://localhost:3000/src/worker1.js?type=module&worker_file:18:1 ```

aws-exports.js

amplifyconfiguration.json:

{
  "aws_project_region": "us-east-1",
  "aws_cognito_identity_pool_id": "us-east-1:0598a33f-9357-4ba8-9cb2-876da7c9bb85",
  "aws_cognito_region": "us-east-1",
  "aws_user_pools_id": "us-east-1_JAAkzlaKS",
  "aws_user_pools_web_client_id": "27s2qe07qgpp0mf7083dian9ua",
  "oauth": {
    "domain": "sandboxauth167bef521-67bef521-dev.auth.us-east-1.amazoncognito.com",
    "scope": [
      "phone",
      "email",
      "openid",
      "profile",
      "aws.cognito.signin.user.admin"
    ],
    "redirectSignIn": "http://localhost:3000/",
    "redirectSignOut": "http://localhost:3000/",
    "responseType": "code"
  },
  "federationTarget": "COGNITO_USER_POOLS",
  "aws_cognito_username_attributes": [
    "EMAIL"
  ],
  "aws_cognito_social_providers": [
    "GOOGLE"
  ],
  "aws_cognito_signup_attributes": [
    "EMAIL"
  ],
  "aws_cognito_mfa_configuration": "OFF",
  "aws_cognito_mfa_types": [
    "SMS"
  ],
  "aws_cognito_password_protection_settings": {
    "passwordPolicyMinLength": 8,
    "passwordPolicyCharacters": []
  },
  "aws_cognito_verification_mechanisms": [
    "EMAIL"
  ],
  "aws_cloud_logic_custom": [
    {
      "name": "sandbox1",
      "endpoint": "https://n66fgb5l98.execute-api.us-east-1.amazonaws.com/dev",
      "region": "us-east-1"
    }
  ]
}

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

cwomack commented 5 months ago

Thanks for creating this issue from the Discord Office Hours session today, @alex-breen. Can you clarify how you're initializing Amplify within the web worker or if it's being imported? And based on the error that you're seeing, can you double check that the API names in the web worker exactly match what's in your config (i.e. casing/spelling)?

alex-breen commented 5 months ago

Side note - I (clumsily) tried a few different things with the web worker to try to make it work. I imported a window polyfill - no change. I called Amplify.configure(amplifyconfig) inside the webworker - I no longer got the invalidAPIName error, but instead got errors about not having authentication credentials. I added authCode into the options field - but I still got errors about missing creds.

cwomack commented 5 months ago

Ok, thanks for the quick response and glad to hear we’re past the original error then at least! It sounds like what’s happening here is you’ve got some type of network requests needing authenticated credentials happening in the web worker. Can you maybe share some additional context here about what you’re trying to do with the web worker?

If you’re trying to offload some of the work to the web worker, you may want to make any networks requests within the main thread but then hand off the response and other work to the web worker after it’s been received for additional processing. If you’re trying to do all this work in the web worker, that error seems like it’ll require you passing credentials into the other thread and require you writing your own credential and token providers (which we wouldn’t recommend).

alex-breen commented 5 months ago

Thanks @cwomack, that's helpful.

Here is the context about why I'm using a web worker:

So, as an alternate method, if I can't invoke the get call from the web worker, I can pass the result back to the main thread and make the post to the API/Lambda from there (like you suggested, just in reverse). The reason I wanted to avoid doing that is so I didn't have to pass large payloads of data between the worker and the main thread. And just to keep the logic in one place.

cwomack commented 3 months ago

@alex-breen, we're going to mark this as a feature request at this point to track better support out of the box for web workers. Appreciate you giving the additional context and use cases here.