Creating a simple web app that shows us how to use TequilAPI
In this tutorial, we are going to make a web app that allows us to manage and view the stats of multiple nodes. We will use the mysterium-vpn-js npm package to interact with our nodes and manage them.
For those who'd like to skip directly to the code, here is a link.
Our web app will consist of 2 parts:
- A React application
- A web proxy
We need to use a web proxy due to CORS limitations. In future, if we can set the CORS origin whitelist within our nodes, we will no longer need it. These limitations are set for security reasons.
To follow this tutorial you first need to meet some requirements:
- Node.js >= 14.0
- Mysterium node port 4449 forwarded in your router
Let's start by building the proxy, as it provides a base for our web app. We are going to use node.js with typescript to develop it.
- Create a new directory called proxy where we will place the proxy code.
- Run yarn init inside the proxy directory to start a new project. You can use the default values.
- Install dependencies using yarn add @types/node typescript and yarn add -D ts-node.
- Create the tsconfig file using yarn tsc --init.
- Create an index.ts file.
- Now let's add some code! We can use default libraries. To create a proxy we will need a server that listens to the requests and forwards them, and then forwards the reply back to us with the correct CORS headers. To create the server we type:
- Then we need to transform our target URL into the correct format. We can call the API using this URL format: http://localhost:5000/proxy/<ip>/<port>/tequilapi/<path> and the proxy will transform it to http://<ip>:<port>/tequilapi/<path>. To do this transformation we can use the following code:
We could add more validity checks to make sure that the URL we are getting is correct, but for now, we'll keep it simple.
- We now want to forward the request to our node, and then forward the response back as our API response while modifying some headers to avoid the CORS issues. To do this, we can use this code:
- We should also add some code to handle request errors. This way, if the address we are given doesn't work, it will notify as an API response instead of crashing:
- Finally, we need to answer the CORS preflight requests. A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood and a server is aware of using specific methods and headers.
For example, the client might be asking a server if it would allow a DELETE request before actually sending one, by using a preflight request. You can learn more about them using this link.
To answer the client that everything is OK, we can use this code at the start of the onRequest function:
We completed our proxy! You can run it by using yarn ts-node ./index.ts or by adding this:
to the root of package.json and using yarn dev.
Web app creation
- Let's start by going to the root of our project and running the create-react-app utility with the typescript option using npx create-react-app --template typescript frontend. This will create a new react project called "frontend".
- Now, to install our dependencies we will use:
- yarn add mysterium-vpn-js: to install the mysterium-vpn-js npm package
- yarn add @material-ui/core: for style, so our web app is not ugly.
- yarn add @material-ui/icons: for the refresh, start, and stop icons.
- This very simple web app will allow us to add nodes, view some stats and be able to turn the Wireguard service on and off. To achieve this, we will modify the App.tsx file. We can start creating some variables to store our data. First, we will create a list of all our nodes addresses, a map to store the data of each node, and some helper functions to manipulate them:
- Let's also create some state variables for our inputs of IP, port, and password, which is the data we need to connect to our nodes. Then we can also add text fields in our HTML code for modifying the variables, as well as a button to trigger the addition of the node:
- For a nice autocomplete experience, we can create a return type for the node data. This is all the data we will save in our nodes Map created in Step 3:
- Now, let's create some functions to add or update a new node. This function will be triggered by our button:
- Let's also add functions to start and stop the node. We will always use our first identity for starting, and the first service for stopping. This is enough for the default node configuration:
- Now let's create the table for displaying the data. We can do it with HTML code and a variable that will transform our node's data into table rows. We will also add a refresh button to trigger the update of all the nodes data:
- Of course, now we need a function to update all the nodes, which is very simple:
- Now we have a working web app that can see node data, and start or stop the service. There is only one thing that is going to bother us; when we refresh the page, all of our added nodes are reset and we have to add them again.
To mitigate this problem, we need to ensure the data persists in the webpage's local storage. We can employ some UseEffect hooks, which will be called when we update our data to save it, and when we load our page to retrieve the data if there is some saved.
We will also use the hooks to check if no API is initialized, which would mean that the nodes' data has just been retrieved from local storage, and therefore we need to refresh all the data to update it and reload the clients.
- Another problem we now have is that the client used to call the API has not persisted in storage, but we have enough information to recreate it. We will create a function to do this, and we will call it in the getNodeData function if the client is not created:
And then this:
We have finally completed our node management web app! Many improvements could be made, but I hope this guide provides inspiration and a good foundation for your future projects which use the node's TequilAPI!
To make the running of both projects easier, we can add this line in the package.json scripts of the frontend project:
And then you can run the project using yarn dev in the frontend folder.