私たちは、ユーザーが自分だけが見ることのできるプライベートネットワークをインターネットの中に構築できるようにすることで、すべてを安全につなぐことができると信じています。ゼロトラストIT/OTネットワーキングをサービスとして提供します。
言語
English
日本
remote.itを使ったことがある人なら、remote.itがダッシュボードを提供し、デバイスやその状態を確認したり、接続したりできることをきっとご存知でしょう。しかし、特定のものを監視する必要がある場合はどうしたらよいでしょうか?
例えば、remote.itは、アカウントキーの認証情報を使って、デバイスに関するデータにアクセスするためのAPIを提供しています。
今回は、GraphQL API を活用して、遠隔地のデバイスやイベントを監視する小さな React App を構築する方法を学びます。
実は、remote.itはREST APIとGraphQL APIも提供しているのです。
そこで、コーディングに入る前に、RESTとGraphQLの主な違いについて説明します。これは、私たちの選択を正当化するのに役立ちます。
組織図
RESTは、6つのアーキテクチャ上の制約に準拠している。
しかし、GraphQLはデータの形状を記述するスキーマと、GraphQLアプリケーションで使用できる様々なデータ型を定義するための型システムで構成されています。
フォーマット
RESTは、XML、JSON、HTML、プレーンテキストなど、多くのフォーマットをサポートしています。GraphQLは、JSONのみをサポートしています。
データ取り込み
REST APIを使用してデータを取得するには、GET、POST、PUT、PATCH、DELETEを使用します。GraphQLでは、Query(データを取得する)またはmutations(オブジェクトを作成、削除、変更する)のタイプでPOSTリクエストを行うだけでよいのです。
以上が、RESTとGraphQLの大きな違いです。
コーディングに飛び込もう
シンプルなReactプロジェクト
まず、React Appのプロジェクトを作成しましょう。
yarn create react-app remoteit-react-graphql
これが終わってプロジェクトがインストールされたら、axios、boostrap、swr、axios-auth-refresh を追加します。
yarn add axios swr axios-auth-refresh react-bootstrap@next bootstrap@5.1.1 react-router-dom
Webページのスタイルにはbootstrapを、APIへのリクエストにはaxiosを使用する予定です。
axios-auth-refreshは、リクエストに使用されている現在のトークンが期限切れの場合、新しいトークンを取得するために使用されます。
RESTおよびGraphQL APIへのリクエストを行う前に、開発者用のAPIキーを使用する必要があります。
このAPIキーは、欲しいデータを取得するためのトークンと共に、各リクエストで送信されます。
自分のキーにアクセスするには、ウェブポータルのアカウントセクション(https://app.remote.it/)にアクセスしてください。
完了したら、ディレクトリprojectに.envファイルを作成します。このファイルには、開発者のAPI KEYやAPI URLなどの機密情報を保存するために使用します。
react_app_api_url=https://api.remote.itREACT_APP_DEV_API_KEY=YOUR 開発者用apiキー
素晴らしい!では、axiosを使って独自のフェッチャーを作ってみましょう。なぜ今作るのか?期限切れのトークンを使ってリクエストを行うので、このトークンが期限切れになったら新しいトークンを請求するのが便利です。インターセプターを書くことにします。
src ディレクトリに 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;
これができたら、今度はLoginページを作成します。
ログイン
ログインページでは、ユーザー名とパスワードの入力が可能です。リクエストが成功した場合は、ダッシュボードページにリダイレクトされます。
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;
お気づきのように、リクエストが成功すると、トークンとservice_authhashがlocalstorageに登録されます。service_authhashは再ログインして新しいトークンを取得する際に使用されます。
使用方法
ログインページの準備ができました。あとは、react-routerをプロジェクトに統合して、ルートの定義を開始します。
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;
それでは、Homeページを追加してみましょう。
デバイスと直近のイベントログを表示する
Home Pageには、デバイスを表示するテーブルと、直近のイベントを表示するテーブルの2つが表示されます。
GraphQL APIでクエリを作成することになります。
ではまず、使用するクエリを書いてみましょう。
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
}
}
}
}
`
}
早速、クエリについて説明しましょう。一般に、どちらのクエリも持っていることに気がつくでしょう。
コンポーネントのロジックを書き始めることができます。
その前に、SWRとaxios.jsに記述したフェッチャーを使ってリクエストしてみましょう。
SWRはデータ取得のためのReactフックです。データのキャッシュと定期的な再バリデーションが可能です。ダッシュボードを定期的に更新するような場合に非常に便利です。
const Home = () => {
const dataDevices = useSWR(‘devices’, () => fetcher(‘/graphql/v1’, devicesQuery));
const dataEvents = useSWR(‘events’, () => fetcher(‘/graphql/v1’, eventsQuery));
return <div></div>
}
そして最後にテンプレート化です。ダッシュボードとテーブルのUIを作成しましょう。
...
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>
)
ダッシュボードはこのように表示されるはずです。
といった感じです。以上、remote.it GraphQL APIを使って、デバイスのイベントとステータスを監視する方法でした。
このAPIは、機器の状態やイベントを取得するだけでなく、より多くの機能を提供します。
また、:
また、これらのリクエストはすべてRESTで行うことができることも忘れてはいけません。これらについては、こちらのドキュメントを自由にご覧ください。
remote.it APIを使い始めるには、こちらのドキュメントをご覧ください。私たちは、あなたがremote.it APIを使ってどんな魅力的なインテグレーションを構築するか、ぜひ見てみたいと思っています。
また、このガイドのコードを見つけたい場合は、こちらのGitHubを参照してください。