user1354825
user1354825

Reputation: 1541

AWS Appsync subscription with postman - No Protocol Error

I am using Postman to connect AWS Appsync subscription as per : https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html

with the below config:

enter image description here

{ "payload": { "errors": [ { "message": "NoProtocolError", "errorCode": 400 } ] }, "type": "connection_error" }

Upvotes: 1

Views: 1961

Answers (3)

Kunal Patil
Kunal Patil

Reputation: 1

Connection URL: Ensure that the WebSocket connection URL is correctly formatted. It should be in the following format:

wss://<your-appsync-api-id>.appsync-realtime-api.<region>.amazonaws.com/graphql

Headers: When connecting, you need to include the appropriate headers:

{
    "host": "<your-appsync-api-id>.appsync-api.<region>.amazonaws.com",
    "x-api-key": "<your-api-key>"
}

Base64 Encoding: Both the header and payload need to be base64 encoded and appended to the connection URL:
Both the header and payload need to be base64 encoded and assembled as follows:

connection_url = WSS_URL + '?header=' + <B64-ENCODED-HEADER> + '&payload=e30=

For the initial connection the payload is always the same (empty JSON object {}). The base 64 representation of {} is: =e30=.

Before connecting to the server, there is one more parameter to set. In the connection request we need to add a secondary protocol graphql-ws

this format for creating subscription worked for me, check it out:

import React, { useEffect, useState } from 'react';

const App = () => {
    const [updates, setUpdates] = useState([]);

    useEffect(() => {
        const headers = {
            "host": "<YOUR_APPSYNC_API_HOST>",
            "x-api-key": "<YOUR_API_KEY>"
        };

        const encodedHeader = btoa(JSON.stringify(headers));
        const payload = "e30="; // Base64 for {}
        const wssUrl = "wss://<YOUR_APPSYNC_REALTIME_API_ENDPOINT>/graphql";
        const connectionUrl = `${wssUrl}?header=${encodedHeader}&payload=${payload}`;

        const ws = new WebSocket(connectionUrl, "graphql-ws");

        ws.onopen = () => {
            console.log("Connected!");
            ws.send(JSON.stringify({ type: "connection_init", payload: {} }));
        };

        ws.onmessage = (event) => {
            const message = JSON.parse(event.data);
            console.log("Received:", message);

            if (message.type === 'connection_ack') {
                const subscriptionMessage = {
                    id: "1", // Unique ID for the subscription
                    type: "start",
                    payload: {
                        data: JSON.stringify({
                            query: `subscription <YOUR_SUBSCRIPTION_NAME>($variable: <VARIABLE_TYPE!>) {
                                <YOUR_SUBSCRIPTION_NAME>(<variable: $variable>) {
                                    <FIELDS_YOU_WANT>
                                }
                            }`,
                            variables: {
                                variable: "<YOUR_VARIABLE_VALUE>" // Replace with actual variable value
                            }
                        }),
                        extensions: {
                            authorization: {
                                "x-api-key": headers["x-api-key"],
                                "host": headers["host"]
                            }
                        }
                    }
                };
                ws.send(JSON.stringify(subscriptionMessage));
            } else if (message.type === 'data' && message.id === '1') {
                const update = message.payload.data.<YOUR_SUBSCRIPTION_NAME>;
                console.log("Update Received:", update);
                setUpdates(prevUpdates => [...prevUpdates, update]);
            } else if (message.type === 'ka') {
                console.log("Keep-alive received");
            }
        };

        ws.onerror = (error) => {
            console.error("Error:", error);
        };

        ws.onclose = (closeEvent) => {
            console.log("Connection closed with code:", closeEvent.code, "and message:", closeEvent.reason);
        };

        return () => {
            ws.close();
        };
    }, []);

    return (
        <div>
            <h1>WebSocket Connection</h1>
            <h2>Updates:</h2>
            <ul>
                {updates.map((update, index) => (
                    <li key={index}>
                        {/* Display your update fields here */}
                        <strong>Update:</strong> {JSON.stringify(update)} <br />
                    </li>
                ))}
            </ul>
        </div>
    );
};

export default App;

Final Notes

Postman Limitations: Postman isn't suitable for testing WebSocket connections directly, as it's primarily an HTTP client. 

Error Handling: Always handle connection errors and other events to maintain a robust application.

Upvotes: 0

Abdulkerim Yıldırım
Abdulkerim Yıldırım

Reputation: 111

if you get this error in unity use this way;

using System.Net.WebSockets;
    
var webSocket = new ClientWebSocket();
webSocket.Options.UseDefaultCredentials = false;
webSocket.Options.AddSubProtocol("graphql-ws");

Upvotes: 1

user1354825
user1354825

Reputation: 1541

The problem occurs due to a missing header:-

Sec-WebSocket-Protocol = graphql-ws

Upvotes: 8

Related Questions