We believe in securely connecting everything by enabling users to build private networks within the internet that only they can see. We provide zero trust IT/OT networking as a service.
Language
English
日本
If you have already used remote.it, you surely know that remote.it provides a dashboard where you can see your devices, their status, and also make connections. But, what if you have to monitor specific things?
For example, remote.it provides an API you can use with your account key credentials to access data about your devices.
In this article, we’ll learn how to make use of the GraphQL API to build a small React App to monitor your remote devices and events.
Actually, remote.it provides a REST API and a GraphQL API as well.
So, before diving into coding, let’s talk about some major differences between REST and GraphQL. This will help us justify our choices.
Organization
REST is compliant with six architectural constraints:
But, GraphQL is organized into schemas to describe the shape of the data and type system, which help you define various data types that can be used in a GraphQL application.
Format
REST supports a lot of formats like XML, JSON, HTML, or plain text. GraphQL supports only JSON.
Data fetching
To fetch data using a REST API, you can use GET, POST, PUT, PATCH, or DELETE. With GraphQL, you just have to make a POST request with the type of Query (to retrieve data) or mutations (to create, delete or modify an object.)
Those are the major differences between REST and GraphQL.
Let’s dive into coding.
Simple React project
First of all, let’s create a React App project.
yarn create react-app remoteit-react-graphql
Once it’s done and the project is installed, we’ll be adding the axios, boostrap, swr and axios-auth-refresh .
yarn add axios swr axios-auth-refresh react-bootstrap@next bootstrap@5.1.1 react-router-dom
We’ll be using bootstrap to style our web page and axios to make requests to the API.
axios-auth-refresh will be used to retrieve a new token if the current token used for requests has expired.
Before making any requests to the REST and the GraphQL API, we need to use the developer API key.
This API key will be sent on each request with a token to retrieve the data we want.
To access your keys, go to the Account section of the web portal on https://app.remote.it/.
Once it’s done, create a .env file in the directory project. We’ll use this file to store sensitive information such as the developer API KEY and the API URL.
REACT_APP_API_URL=https://api.remote.itREACT_APP_DEV_API_KEY=YOUR DEVELOPER API KEY
Great, now let’s create our own fetcher using axios. Why create now? As we are making requests with a token that will expire, it’ll be useful to claim a new token if this one is expired. We’ll be writing an interceptor.
In the src directory, create a file axios.js.
import axios from “axios”;
import createAuthRefreshInterceptor from “axios-auth-refresh”;
import {useHistory} from “react-router-dom”;
const axiosService = axios.create({
baseURL: process.env.REACT_APP_API_URL,
headers: {
‘Content-Type’: ‘application/json’,
‘apikey’: process.env.REACT_APP_DEV_API_KEY
}
});
axiosService.interceptors.request.use(async (config) => {
const token = localStorage.getItem(‘token’);
if (token){
config.headers.token = token;
console.debug(‘[Request]’, config.baseURL + config.url, JSON.stringify(token));
}
return config;
})
axiosService.interceptors.response.use(
(res) => {
console.debug(‘[Response]’, res.config.baseURL + res.config.url, res.status, res.data);
return Promise.resolve(res);
},
(err) => {
console.debug(
‘[Response]’,
err.config.baseURL + err.config.url,
err.response.status,
err.response.data
);
return Promise.reject(err);
}
);
const refreshAuthLogic = async (failedRequest) => {
const authHash = localStorage.getItem(‘authHash’)
const username = localStorage.getItem(‘username’);
const history = useHistory();
if (authHash) {
return axios
.post(
‘/apv/v27/user/login’,
{
username: username,
authhash: authHash
},
{
baseURL: process.env.REACT_APP_API_URL
}
)
.then((resp) => {
const { token, service_authhash } = resp.data;
failedRequest.response.config.headers.token = token;
localStorage.setItem(“authHash”, service_authhash);
localStorage.setItem(‘token’, token);
})
.catch((err) => {
if (err.response && err.response.status === 401){
history.push(‘/login’);
}
});
}
};
createAuthRefreshInterceptor(axiosService, refreshAuthLogic);
export function fetcher(url, data) {
return axiosService.post(url, data).then((res) => res.data);
}
export default axiosService;
Once it’s done, we can now create the Login page.
Login
The Login page allows entering a username and a password. If the request is successful, then we redirect to the dashboard page.
import React, {useState} from “react”;
import axios from “axios”;
import {useHistory} from “react-router-dom”;
const Login = (key, value) => {
const history = useHistory();
const [email, setEmail] = useState(“”);
const [password, setPassword] = useState(“”);
const [error, setError] = useState(“”);
function handleSubmit(event) {
event.preventDefault();
axios.post(`${process.env.REACT_APP_API_URL}/apv/v27/user/login`, {
username: email,
password: password
}, {
headers: {
“Content-Type”: “application/json”,
“apikey”: process.env.REACT_APP_DEV_API_KEY
}
}).then( r => {
localStorage.setItem(“username”, email);
localStorage.setItem(“authHash”, r.data.service_authhash);
localStorage.setItem(‘token’, r.data.token)
history.push(‘/home’)
}).catch(e => {
setError(e.response.data.reason);
})
}
return (
<div className=”w-25 mh-100″>
<form onSubmit={handleSubmit}>
<div className=”form-group m-2″>
<label htmlFor=”email”>Email address</label>
<input
className=”form-control my-2″
required
id=”email”
type=”email”
name=”username”
placeholder=”Email address”
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className=”form-group m-2″>
<label htmlFor=”password”>Password</label>
<input
className=”form-control my-2″
id=”password”
required
type=”password”
name=”password”
placeholder=”Password”
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<button type=”submit” className=”btn btn-primary m-2″>Submit</button>
</form>
{error && <div>{error}</div>}
</div>
)
}
export default Login;
As you can notice, if the request is successful, we register the token and the service_authhash in the localstorage. The service_authhash will be used to log in again and retrieve a new token.
Usage
The Login page is ready. it’s time to integrate react-router to the project and start defining routes.
import {
BrowserRouter as Router,
Switch,
Route,
} from “react-router-dom”;
import Login from “./Login”;
import Home from “./Home”;
import “bootstrap/dist/css/bootstrap.min.css”;
function App() {
return (
<div className=”container-fluid”>
<Router>
<Switch>
<Route exact path=”/” component={Login} />
<Route exact path=”/home” component={Home} />
</Switch>
</Router>
</div>
);
}
export default App;
Let’s add the Home page now.
Displaying the devices and the most recent events logs
The Home Page will contain two tables: one to display the devices and one for the last events.
We’ll be making queries on the GraphQL API.
So first of all, let’s write the queries we’ll use.
import React from “react”;
import useSWR from ‘swr’
import {fetcher} from “./axios”;
const devicesQuery = {
query: `{
login {
devices(size: 1000, from: 0) {
total
hasMore
items {
id
name
hardwareId
created
state endpoint{geo{latitude longitude}}
}
}
}
}
`
}
const eventsQuery = {
query: `{
login {
events {
hasMore
total
items {
type
owner {
}
actor {
}
target {
created
id
name
}
users {
}
timestamp
}
}
}
}
`
}
Let’s quickly describe the queries. In general, you can notice that both queries have:
We can start writing the logic of our component.
But first of all, let’s make requests using SWR and the fetcher we’ve written on the axios.js file.
SWR is React hook for data fetching. It allows data caching and periodic revalidation. Very useful in this case where we want the dashboard to refresh itself periodically.
const Home = () => {
const dataDevices = useSWR(‘devices’, () => fetcher(‘/graphql/v1’, devicesQuery));
const dataEvents = useSWR(‘events’, () => fetcher(‘/graphql/v1’, eventsQuery));
return <div></div>
}
And finally the templating. Let’s create the UI for the dashboard and the tables.
…
return (
<div>
<div className=”m-5″>
<h3 className=”h3″>Number of devices: {dataDevices.data?.data?.login?.devices?.total}</h3>
<table className=”table table-hover”>
<thead>
<tr>
<th scope=”col”>Device id</th>
<th scope=”col”>Name</th>
<th scope=”col”>hardwareId</th>
<th scope=”col”>Created</th>
<th scope=”col”>State</th> <th scope=”col”>Geo localisation</th>
</tr>
</thead>
<tbody>
{
dataDevices.data?.data?.login?.devices?.items.map((device, index) =>
{
console.log(device);
return <tr>
<th scope=”row”>{device.id}</th>
<td>{device.name}</td>
<td>{device.hardwareId}</td>
<td>{formatDate(device.created)}</td>
<td className={getStatusColor(device.state)}>{device.state}</td> <td><a href={`https://www.google.com/maps/place/${device.endpoint.geo.latitude},${device.endpoint.geo.longitude}`} target=”_blank”
rel=”noopener noreferrer”>See localisation</a></td>
</tr>
}
)
}
</tbody>
</table>
</div>
<hr />
<div className=”m-5″>
<h3 className=”h3″>Number of events: {dataEvents.data?.data?.login?.events?.total}</h3>
<table className=”table table-hover”>
<thead>
<tr>
<th scope=”col”>Type</th>
<th scope=”col”>Owner</th>
<th scope=”col”>Actor</th>
<th scope=”col”>Target Name</th>
<th scope=”col”>Time</th>
</tr>
</thead>
<tbody>
{
dataEvents.data?.data?.login?.events?.items?.map((event, index) => (
<tr>
<th scope=”row”>{event.type}</th>
<td>{event.owner?.email}</td>
<td>{event.actor?.email}</td>
<td>{event.target?.map((target, index) => (
<p>{target.name} |</p>
))}</td>
<td>{event.timestamp}</td>
</tr>
))
}
</tbody>
</table>
</div>
</div>
)
The dashboard should look like this.
And that’s it. That’s how you can use the remote.it GraphQL API to monitor the events and the status of your devices.
The API provides more features than just retrieving the status of your devices and the events.
You can also :
And also don’t forget that you can make all these requests with REST. Feel free to check the documentation for these here.
To get started using the remote.it API, you can find the documentation here. We’d love to see what fascinating integrations you build with the remote.it API.
And if you want to find the code of this guide, you can check GitHub here.