YellowfinのRESTAPIをJavaScriptから使用する

# 概要
なんだかやったことあるような気がしたんですが、SSOくらいしか試せてなくて実際に使うにはどういう流れになるか不明だったので今回まとめてみました。

# ハマリポイントについて
ハマリポイントは固有のAuthorizationヘッダーの部分がなかなかユニークなので、UnixTimeStampを使う必要があったり、最初にどのAPIを使ってsecurityTokenを取得するんだ！？とかですね。。
実際にやってみた時には似たようなAPIがあったりしてわかりづらかったです。
まずは公式wikiの[このページ](https://wiki.yellowfin.co.jp/display/yfcurrent/REST+API)を見て試行錯誤です。

## どのAPIを使ってsecurityTokenを取得するのか
まず、単純にSSOしてレポートやダッシュボードを表示したいというだけであれば、[CORS設定を行いwebserver越しにRESTでYellowfinサーバーにアクセスする](https://qiita.com/celery/items/69f8da9601277807cc34)や[Yellowfinのクライアント組織に属している人向けのJSAPIv3でのダッシュボード表示](https://qiita.com/celery/items/2428fd35d37cb5b2bd65)のように/api/rpc/login-tokens/create-sso-tokenのAPIを使えばいい感じです。

今回はログインしてトークン取得してからの実際他の機能のAPIを使用したいので、**/api/refresh-tokens**を使えばいいようです。

## Responseのどの値を使えばいいのか
実際のResponseの一部がこちらです。securityTokenが2箇所あるんですよね。。わかりづらい！
これから使用するのはアクセスするためのsecurityTokenだからなのか、**_embedded.accessToken.securityToken**の値を使います。。一番最初のsecurityTokenはリフレッシュトークンなので、これを保持してここからアクセストークンを取得したりと言った場合に使いますが、RESTAPIを使うだけならアクセストークンだけで大丈夫です。

(2021/06/07追記)
/api/refresh-tokens で返ってくるセキュリティトークンが2つあるのは、片方がリフレッシュトークンで、もう一方がアクセストークンだからという指摘を頂きました。
リフレッシュトークンは永続的なやつ（値を保管しておいてAPI呼び出し時に毎回使う用）で、アクセストークンは一時的なやつですね。
でも、/とか+とかってヘッダーで使えたっけな・・・？この辺も詳しく調べてませんがBase64とかで暗号化してあるのかもしれないですね。

```
{
    "securityToken": "XnWbIbEHElGmyuIpxPct3r0h6PVa6l8vVXhlHHa6qK49I3YT9E65XyVnEEq3WXt85k4Y4/nlrqyLWu4bAV9A4bTX1AnqVEAPnc834rKkAQZVFtNIpHj4LanrQI3Pe0Vw8QV+az6+ss47fun36cDViD++CnY9LJdpj8Pv4wsqxnQIoxOLGMtKUSx8MapgdoVuBMjad8bVhj1H1jaUzm/SQPYJDHVr/mR38Ux7xspC+zddW1+k4Md7xXICL+ghVxWFq7+8QDAp2X4sw/FBl5dfg9sAYR3zyGLqa9dxkEFi8xmWM7+MkVxMRG1JgAPOXObOelJIuJFwBNkXQN27vCEp9g==",
    "tokenId": "107827",
    "_links": {
        "menu": {
            "href": "/api/menus/mobile-menu",
            "options": [
                "GET"
            ]
        },
        "api": {
            "href": "/api",
            "options": [
                "GET"
            ]
        },
        "self": {
            "href": "/api/refresh-tokens/107827",
            "options": [
                "DELETE"
            ]
        }
    },
    "_embedded": {
        "accessToken": {
            "securityToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiWUZBRE1JTiIsInRpIjoxMDc4MjcsInBlcnNvbiI6IjUiLCJjbGllbnQiOiIxIiwiZXhwIjoxNjIxOTkxMTQxLCJpYXQiOjE2MjE5ODk5NDF9.oF5ok7RYIiHUM3HLg9px3WGUbrVDGp32psGoqbKE9ew",
            "expiry": 1200,
            "_links": {
                "new": {
                    "href": "/api/access-tokens",
                    "options": [
                        "POST"
                    ]
                }
            }
        },
        "user": {
〜〜〜略
```

## Authorizationヘッダーについて
概要で触れたハマリポイントのAuthorizationヘッダーですが、公式wikiにもあるようにtsの値を**unixTimeStampのミリ秒**にすることが必要です。なので、Postmanなどで検証するときはhttps://tools.m-bsys.com/development_tooles/unix_time.php などでミリ秒まで取得できるところを使ったほうがいいです。他のところでも0を3つつければいいんですけどね。
また、最初の/api/refresh-tokensを使用する際は、BodyにCredentialを含めるのでTokenは必要ないのですが、それ以外の場合は取得したTokenを使ってアクセスする必要があります。
最初のYELLOWFIN ts=の部分までは共通で、nonseの値は任意の値でいいようです。

# ソースコード
とにかく実装はこちらです。コメントの部分を変更したり外したりするとよりわかりやすいかもしれません。

```javascript:getOrgs.html
<html>

<head>
	<meta charset="utf-8" />
	<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
</head>

<body>
	<script>
		var authUserId = 'admin@yellowfin.com.au';
		var authUserPass = 'test';
		var body = {
			"userName": authUserId,
			"password": authUserPass
		};
		//encode to JSON
		var json_text = JSON.stringify(body);
		var xhr = new XMLHttpRequest();
		xhr.open('POST', 'http://localhost:8940/api/refresh-tokens');
		xhr.responseType = 'json';
		xhr.setRequestHeader('Authorization', 'YELLOWFIN ts=' + new Date().getTime() + ', nonce=123');
		xhr.setRequestHeader('Accept', 'application/vnd.yellowfin.api-v1.2+json');
		xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
		xhr.onload = () => {
			var securityToken = xhr.response._embedded.accessToken.securityToken;
			var xhr2 = new XMLHttpRequest();
			xhr2.open('GET', 'http://localhost:8940/api/orgs');
			//xhr2.open('GET', 'http://localhost:8940/api/users');
			xhr2.responseType = 'json';
			xhr2.setRequestHeader('Authorization', 'YELLOWFIN ts=' + new Date().getTime() + ', nonce=123, token=' + securityToken);
			xhr2.setRequestHeader('Accept', 'application/vnd.yellowfin.api-v1.2+json');
			xhr2.onload = () => {
				var items = xhr2.response.items;
				console.log(items);
//				items.forEach(item => {
//					console.log(item.name);
//				});
			};
			xhr2.send();
		};
		xhr.send(json_text);
	</script>
</body>

</html>

```

実際に表示されるDeveloperToolのコンソールはこちらです。xhr2.response.itemsの中身で、これは最初にTokenを取得したユーザーがログイン可能なクライアント組織を取得しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223443/ea4d8424-23ca-e494-295b-12afbc7eb25d.png)

# かんそう
わかりづらかったですね！公式の[開発者サイト](https://developers.yellowfinbi.com/dev/api-docs/yf-api.html)には実装のソースまでは載っていないので結構模索しました。。
実際のAPIを使える段階になると便利な機能がAPIで実装されているので、まずはこれが役に立てれば幸いです。。。