Version: Next

# Demo - Boomerang Chat

Boomerang Chat is a simple app that sends a message to the HOPR Network and returns it to the sender. Because nodes in the network have no idea who sent the message and who’s the final recipient, a node can always send a message to itself, and no other node would be any the wiser. HOPR nodes only know who to forward the message to next.

This demo showcases the minimal requirements needed to build a HOPR app. Boomerang Chat is a React-based web application that uses native WebSockets to connect to your HOPR node and its REST API to send messages to itself.

## Requirements​

• a HOPR cluster, and at least a single HOPR node with its respective HTTP_ENDPOINT, WS_ENDPOINT and API_TOKEN
• a React-ready web framework used to run the application. We recommend next.js.

For simplicity, you can also see the code for this demo in Codesandbox. To see an example of how to run this as an isolated application, you can also check our demo chat application, MyneChat.

## Building the Boomerang Chat​

### 1. Connecting to our HOPR nodes​

Our React application starts like any other: simply loading the application within an entry point.

index.jsx (usually your React application entrypoint)
import { render } from 'react-dom'import BoomerangChat from './BoomerangChat'const rootElement = document.getElementById('root')render(<BoomerangChat />, rootElement)

We can see how we are loading our app in line 3 and rendering it on line 6. BoomerangChat.jsx renders the actual component we are looking to build as a HOPR App, so let's take a look at BoomerangChat.jsx:

BoomerangChat.jsx
import React, { useEffect, useState } from "react";import WebSocketHandler from "./WebSocketHandler";export default function BoomerangChat() {  const [message, setMessage] = useState("Hello world");  const [securityToken, setSecurityToken] = useState("");  const [wsEndpoint, setWsEndpoint] = useState("ws://localhost:3000");  const [httpEndpoint, setHTTPEndpoint] = useState("http://localhost:3001");  const [address, setAddress] = useState("");  useEffect(() => {    const loadAddress = async () => {      ...    };    loadAddress();  }, [securityToken, httpEndpoint]);  const sendMessage = async () => {    ...  };  return (    <div>      ...      <WebSocketHandler wsEndpoint={wsEndpoint} securityToken={securityToken} />    </div>  );}

From lines 6 to 8, we see a series of values called httpEndpoint, wsEndpoint, and securityToken. These are needed in most HOPR Applications. Without these values, which are configurable by the user, HOPR apps cannot communicate with HOPR nodes.

In line 25, we see a component called WebSocketHandler. Here is its code:

WebSocketHandler.jsx
import React, { useEffect, useState } from "react";import useWebsocket from "../hooks/useWebSockets ";export const WebSocketHandler = ({ wsEndpoint, securityToken }) => {  const [message, setMessage] = useState("");  const websocket = useWebsocket({ wsEndpoint, securityToken });  const { socketRef } = websocket;  const handleReceivedMessage = async (ev) => {    ...  };  useEffect(() => {    if (!socketRef.current) return;    socketRef.current.addEventListener("message", handleReceivedMessage);    return () => {      if (!socketRef.current) return;      socketRef.current.removeEventListener("message", handleReceivedMessage);    };  }, [socketRef.current]);  ...};

Here's where things start getting interesting.

1. We are attempting to connect to our HOPR node WebSocket endpoint on load, and
2. When we succeed, we attach an event handler to every message it receives.

Of course, you could always just try and connect on request rather than on load. For now, the easiest way is to use the useWebSocket helper (you can find the code at the bottom of this page) to initialize the WebSocket interface and retries on changes to the wsEndpoint value.

In addition to the WebSocket endpoint, a HOPR app should also try to use a HOPR node's REST API endpoint to display useful information about it in the app, such as address and balance.

In our previous example, inside BoomerangChat.jsx we had a useEffect call, which goes something like this:

BoomerangChat.jsx
useEffect(() => {  const loadAddress = async () => {    const headers = getHeaders()    const account = await fetch(${httpEndpoint}/api/v2/account/addresses, { headers }) .then((res) => res.json()) .catch((err) => console.error(err)) setAddress(account?.hoprAddress) } loadAddress()}, [securityToken, httpEndpoint]) In line 4, we are talking to the node's REST API using the native fetch call to obtain its HOPR Address since we’ll be using that later when we want to send a message. It's important to include the Headers (see next line) which authenticates the client against the call to avoid unauthorized calls. Here's the getHeaders method for reference: getHeaders method const getHeaders = (isPost = false) => { const headers = new Headers() if (isPost) { headers.set('Content-Type', 'application/json') headers.set('Accept-Content', 'application/json') } headers.set('Authorization', 'Basic ' + btoa(securityToken)) return headers} ### 3. Sending the message via the REST API​ The final part of the demo revolves around the actual request to send the message. We can see the code from the same file here: BoomerangChat.jsx const sendMessage = async () => { if (!address) return await fetch(${httpEndpoint}/api/v2/messages, {    method: 'POST',    headers: getHeaders(true),    body: JSON.stringify({      recipient: address,      body: message    })  }).catch((err) => console.error(err))}

We can see that the message is being sent via the REST API endpoint, including also headers (which are now different) since we are making a POST request. The important part is on line 7, where we state the recipient of the message is address, a value which we set up in the initial useEffect request. This is how we are signalling to the API to send a message to that particular address, which happens to be ourselves. For the HOPR Network, the destination of the message is irrelevant.

### Demo: Boomerang​

You can see the application working and running on this same page. Give it a try! Don’t forget that you need at least a running HOPR cluster for it to work.

You have no messages.

### Annex: Components/hooks code​

Here's all the code for all components and hooks used.

#### useWebSocket.js​

Used as a WebSocket interface to react and connect to our HOPR node accordingly.

useWebSocket.js