little-bear-labs / aws-utils

Apache License 2.0
56 stars 35 forks source link

appsync-serverless-emulator: how to work with subscriptions #48

Open SET001 opened 5 years ago

SET001 commented 5 years ago

I'm testing this with GraphQl Playground (connected to http://localhost:62222/graphql) - mutations and queries working fine but it I'm trying to run subscription I'm getting this error:

{
  "error": "Could not connect to websocket endpoint ws://localhost:62222/graphql. Please check if the endpoint url is correct."
}

should I connect playground elsewhere or how do I make this work?

when I start emulator I got this:

started at url: http://localhost:62222/graphql

so - no mentions that it is listening websockets

cbaron commented 5 years ago

See here

Server can be found here:

ws://localhost:62222/

@SET001 -- will you please update the README so others can look this up in the documentation?

SET001 commented 5 years ago

this is still does not work. If I use ws://localhost:62222/ the response is:

{
  "error": "Failed to fetch schema. Please check your connection"
}

should I maybe additionally enable it somehow?

cbaron commented 5 years ago

Different error is progress!

I cannot help you without more info.

SET001 commented 5 years ago

hope this will help emulator is just not listening on ws://localhost:62222/

cbaron commented 5 years ago

Looks like its trying to reach: ws://localhost:62222/graphql. which is the wrong location

SET001 commented 5 years ago

as you can se, I'm using ws://localhost:62222/ in the address bar. Does requesting ws://localhost:62222/graphql instead ws://localhost:62222 mean this is a bug of GraphQl Playground? What do you use to test it locally?

cbaron commented 5 years ago

We like to write tests in jest.

You can, update this line of code: https://github.com/ConduitVC/aws-utils/blob/71ae2f3774540b425b70fb56a2836bf0b963f75d/packages/appsync-emulator-serverless/serverCore.js#L307 to use /graphql to see if it works for you, or you can write unit tests

We like jest, see here as an example

SET001 commented 5 years ago

Server can be found here:

ws://localhost:62222/

Shouldn't ws and http ports be different? Also I see that in code you pointed there is used port 0 which became a default port on runtime

SET001 commented 5 years ago

I was only able to run subscription after patching here to some port value (62255) and then to make playground work with this - setting it in .graphqlconfig as described here

cbaron commented 5 years ago

@SET001, my bad, you're right, ws://localhost:62222/ was an incorrect thing to post.

As you can see in serverCore.js L307

 const mqttURL = `ws://localhost:${mqttHTTP.address().port}/`; 

The web socket is available here: mqttHTTP.address().port

If you want to make it configurable, or have it logged as output, please submit a PR.

Also, curious why you're using prisma and appsync ?

SET001 commented 5 years ago

I'm using graphql-playground as a client to test appSync queries locally with your emulator )

SET001 commented 5 years ago

I have made a pull request with configurable websocket port. With it my graphql client connects to subscription but there never triggered when mutation happens. In common, for subscription to work, I have to define them in schema:

type Subscription{
    createdTransaction(reservationId: Int): Transaction
    @aws_subscribe(mutations: ["createTransaction"])
}

and no additional records in serverless.yml is required, correct? If I want to use what is called local resolver - to send data from mutation directly to subscriber....

cbaron commented 5 years ago

See here for our tested example serverless.ylm which includes subscriptions.

this is the corresponding schema

Our code is tested using the appsync client, not the prisma client, so I cannot speak for how that will work.

SET001 commented 5 years ago

I still not getting anything on subscription...

there are few callbacks here and here that should give some output whenever I connect and subscribe but I don`t get any... however I know that ws-connection is made on ws-port... I see that GraphQl Playground connected, I also used few Chrome extension to test this ws-connection. But I don't get any data from this subscription on mutation. I don't even get messages about that subscription server is connected/subscribed...

Please, I need help.

SET001 commented 5 years ago

also, how do I run emulators tests?

cbaron commented 5 years ago

@SET001 -- I cannot help you without more information.

I strongly urge you to use an AppSync client to interact with the AppSync emulator as a different client is not guaranteed to work out of the box.

To run tests: yarn jest packages/appsync-emulator-serverless

SET001 commented 5 years ago

I strongly urge you to use an AppSync client to interact with the AppSync emulator

do you mean this one - https://github.com/awslabs/aws-mobile-appsync-sdk-js? I need something with GUI for handy testing )

SET001 commented 5 years ago

the tests are failing, btw:

set@set-home ~/www/aws-utils $ yarn jest packages/appsync-emulator-serverless
yarn run v1.9.4
$ /home/set/www/aws-utils/node_modules/.bin/jest packages/appsync-emulator-serverless
 PASS   lint  packages/appsync-emulator-serverless/__test__/lambdaRunner.test.js
 PASS   lint  packages/appsync-emulator-serverless/loadServerlessConfig.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/httpSource.test.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/server.test.js
 PASS   lint  packages/appsync-emulator-serverless/vtl.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/loadServerlessConfig.test.js
 PASS   lint  packages/appsync-emulator-serverless/schemaTest.js
 PASS   lint  packages/appsync-emulator-serverless/tester.js
 PASS   lint  packages/appsync-emulator-serverless/schemaWrapper.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/tester.test.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/schemaTest.test.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/mqttClient.js
 PASS   lint  packages/appsync-emulator-serverless/httpSource.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/lambdaFunctions.js
 PASS   lint  packages/appsync-emulator-serverless/lambdaSource.js
 PASS   lint  packages/appsync-emulator-serverless/server.js
 PASS   lint  packages/appsync-emulator-serverless/paho.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/example/handler.js
 PASS   lint  packages/appsync-emulator-serverless/lambdaRunner.js
 PASS   lint  packages/appsync-emulator-serverless/jest.js
 PASS   lint  packages/appsync-emulator-serverless/bin/server.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/util.test.js
 PASS   lint  packages/appsync-emulator-serverless/schema.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/example/serverless.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/dynamodbSource.test.js
 PASS   lint  packages/appsync-emulator-serverless/log.js
 PASS   lint  packages/appsync-emulator-serverless/testJWT.js
 PASS   lint  packages/appsync-emulator-serverless/util.js
 PASS   lint  packages/appsync-emulator-serverless/serverCore.js
 PASS   lint  packages/appsync-emulator-serverless/__test__/vtl.test.js
 PASS   lint  packages/appsync-emulator-serverless/dynamodbSource.js
 PASS   test  packages/appsync-emulator-serverless/__test__/vtl.test.js
 PASS   test  packages/appsync-emulator-serverless/__test__/httpSource.test.js
(node:27466) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
 PASS   test  packages/appsync-emulator-serverless/__test__/util.test.js
 PASS   test  packages/appsync-emulator-serverless/__test__/lambdaRunner.test.js
 PASS   test  packages/appsync-emulator-serverless/__test__/loadServerlessConfig.test.js
 PASS   test  packages/appsync-emulator-serverless/__test__/dynamodbSource.test.js

 RUNS   test  packages/appsync-emulator-serverless/__test__/schemaTest.test.js
 FAIL   test  packages/appsync-emulator-serverless/__test__/tester.test.js
  ● Console

    console.warn node_modules/node-uuid/uuid.js:48
      [SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()

  ● appasync-emulator-serverless/tester › client interactions

    listen EADDRINUSE :::1883

      at node_modules/@conduitvc/mosca/lib/server.js:225:16
      at makeCall (node_modules/fastseries/series.js:119:7)
      at NoResultsHolder.release (node_modules/fastseries/series.js:67:9)
      at series (node_modules/fastseries/series.js:39:14)
      at Object.eachSeries (node_modules/steed/steed.js:47:5)
      at node_modules/@conduitvc/mosca/lib/server.js:211:13
      at makeCall (node_modules/fastseries/series.js:117:7)

  ● appasync-emulator-serverless/tester › client interactions

    TypeError: Cannot read property 'url' of undefined

      52 | 
      53 | const connect = (
    > 54 |   serverConfig,
         |                       ^
      55 |   AWSAppSyncClient,
      56 |   AUTH_TYPE = 'AMAZON_COGNITO_USER_POOLS',
      57 |   configs = {},

      at connect (packages/appsync-emulator-serverless/tester.js:54:23)
      at Object.it (packages/appsync-emulator-serverless/__test__/tester.test.js:23:20)

  ● appasync-emulator-serverless/tester › client interactions

    TypeError: Cannot read property 'close' of undefined

      18 |   });
      19 | 
    > 20 |   afterEach(async () => serverSetup.close());
         |                                     ^
      21 | 
      22 |   it('client interactions', async () => {
      23 |     const client = connectTestServer(serverSetup, AWSAppSyncClient);

      at Object.afterEach (packages/appsync-emulator-serverless/__test__/tester.test.js:20:37)

 PASS   test  packages/appsync-emulator-serverless/__test__/server.test.js
  ● Console

    console.warn node_modules/node-uuid/uuid.js:48
      [SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()
    console.log packages/appsync-emulator-serverless/serverCore.js:313
      listening for subscriptions at: ws://localhost:38044/
    console.log node_modules/apollo-boost/lib/index.js:54
      [GraphQL error]: Message: No request, Location: [object Object], Path: error
    console.log packages/appsync-emulator-serverless/serverCore.js:313
      listening for subscriptions at: ws://localhost:43789/
    console.log packages/appsync-emulator-serverless/serverCore.js:313
      listening for subscriptions at: ws://localhost:39607/
    console.log packages/appsync-emulator-serverless/serverCore.js:313
      listening for subscriptions at: ws://localhost:38588/
    console.log packages/appsync-emulator-serverless/serverCore.js:313
      listening for subscriptions at: ws://localhost:43186/

 PASS   test  packages/appsync-emulator-serverless/__test__/schemaTest.test.js

Summary of all failing tests
 FAIL  packages/appsync-emulator-serverless/__test__/tester.test.js
  ● appasync-emulator-serverless/tester › client interactions

    listen EADDRINUSE :::1883

      at node_modules/@conduitvc/mosca/lib/server.js:225:16
      at makeCall (node_modules/fastseries/series.js:119:7)
      at NoResultsHolder.release (node_modules/fastseries/series.js:67:9)
      at series (node_modules/fastseries/series.js:39:14)
      at Object.eachSeries (node_modules/steed/steed.js:47:5)
      at node_modules/@conduitvc/mosca/lib/server.js:211:13
      at makeCall (node_modules/fastseries/series.js:117:7)

  ● appasync-emulator-serverless/tester › client interactions

    TypeError: Cannot read property 'url' of undefined

      52 | 
      53 | const connect = (
    > 54 |   serverConfig,
         |                       ^
      55 |   AWSAppSyncClient,
      56 |   AUTH_TYPE = 'AMAZON_COGNITO_USER_POOLS',
      57 |   configs = {},

      at connect (packages/appsync-emulator-serverless/tester.js:54:23)
      at Object.it (packages/appsync-emulator-serverless/__test__/tester.test.js:23:20)

  ● appasync-emulator-serverless/tester › client interactions

    TypeError: Cannot read property 'close' of undefined

      18 |   });
      19 | 
    > 20 |   afterEach(async () => serverSetup.close());
         |                                     ^
      21 | 
      22 |   it('client interactions', async () => {
      23 |     const client = connectTestServer(serverSetup, AWSAppSyncClient);

      at Object.afterEach (packages/appsync-emulator-serverless/__test__/tester.test.js:20:37)

Test Suites: 1 failed, 1 skipped, 39 passed, 40 of 41 total
Tests:       1 failed, 1 skipped, 106 passed, 108 total
Snapshots:   0 total
Time:        9.2s
cbaron commented 5 years ago

I strongly urge you to use an AppSync client to interact with the AppSync emulator

do you mean this one - https://github.com/awslabs/aws-mobile-appsync-sdk-js? I need something with GUI for handy testing )

My apologies, but there is no GUI for testing the app sync emulator locally. I would suggest you write tests in jest, or build a web client that you can test manually. See here for an example of a test script.

Looks like your tests are failing because port 1883 is being used. Try running them again perhaps.

SET001 commented 5 years ago

Seems like the problem is that you are using mosca - mqtt broker as a subscription server. While GraphQl Playground uses subscriptions-transport-ws. I have made attempt to rewrite emulator from using mosca to subscriptions-transport-ws and then it eventually worked fine. So now the question - can we switch to subscriptions-transport-ws in whole emulator, or can we at least make is somehow configurable so that it would be possible to switch from using one to another?

cbaron commented 5 years ago

I have made attempt to rewrite emulator from using mosca to subscriptions-transport-ws and then it eventually worked fine.

But does it work fine when you use AWS's AppSync client?

We use mosca mqtt broker as a subscription server so that we can emulate AWS's AppSync service locally. If we switch to using subscriptions-transport-ws, we will likely break compatibility with AWS's AppSync client.

You are welcome to make subscriptions configurable so that one can use subscriptions-transport-ws in order to utilize GraphQL playground.

You are welcome to rewrite the whole emulator subscription engine as long as it works with the AppSync client.

SET001 commented 5 years ago

we will likely break compatibility with AWS's AppSync client.

No, it should not. Hold on, I'll make some tests and return with results and maybe PR

SET001 commented 5 years ago

as long as it works with the AppSync client.

what exact client library would you like to be supported? What I see from tests it is apollo-boost which uses apollo-client under the hood. Or aws-mobile-appsync-sdk-js client (which is also using apollo-client)? Currently I made it work with apollo-client. Is it ok?

cbaron commented 5 years ago

The point of this repo is to be able to develop locally, and ultimately push the code to AWS's AppSync, therefore it must work with aws-mobile-appsync-sdk-js