SPARQList

提供:TogoWiki

移動: 案内, 検索

SPARQList は SPARQL クエリの結果を(必要なら JavaScript で加工して)クライアントに返す REST API を提供するためのミドルウェアです。

目次

主な機能

  • Markdown で SPARQL クエリのドキュメントが書ける
  • SPARQL の結果を JavaScript で任意に加工できる
  • 多段の SPARQL や JavaScript の結果を組み合わせて最終的なデータを生成できる
  • ウェブの UI から REST API のロジックを編集したり、オプションを変更できる
  • コンテントネゴシエーションで json の他に text や csv など色々なデータを返すこともできる

レポジトリ

  • https://github.com/dbcls/sparqlist
    • 2018-02-08 ver. からパラメータがグローバル変数に
    • 2018-02-20 ver. から POST 受信可、JavaScript 内で fetch 利用可
      • multipart/form-data の POST は不可

インストール

node.js の最新版をインストール(展開して bin/node, bin/npm を ~/local/bin などにリンクする)

$ wget --no-check-certificate https://nodejs.org/dist/v7.7.2/node-v7.7.2-linux-x64.tar.xz
$ npm install yarn -g

sparql-proxy の現状版をダウンロードしてインストール

$ git clone https://github.com/dbcls/sparqlist.git
$ cd sparqlist
$ ROOT_PATH=/rest/ yarn install

ここで ROOT_PATH=/rest/ は http://localhost:3000/ の代わりに http://localhost:3000/rest/ などのサブパスに SPARQList をデプロイするための設定。

起動方法

$ ROOT_PATH=/rest/ PORT=3000 ADMIN_PASSWORD=xxxxx yarn start

これで http://localhost:3000/rest/ を開けば OK。

デプロイ例

おまけ

デーモン化する場合

$ npm install forever -g

インストール先が /opt/sparqlist/git で yarn が /opt/sparqlist/local/bin にある場合

$ cat startup.sh
#!/bin/sh

export PATH="/opt/sparqlist/local/bin:$PATH"
(cd /opt/sparqlist/git; ROOT_PATH=/rest/ PORT=xxxxx ADMIN_PASSWORD=xxxxx forever --workingDir=/opt/sparqlist/git /opt/sparqlist/local/bin/yarn start > yarn.log)

使い方

Markdown で SPARQL クエリや JavaScript を記述する。

# Organism images

## Parameters

* `tax` Taxonomy ID
  * default: 4896
  * examples: 9606, 4896, ...

## Endpoint

http://dev.togogenome.org/sparql-test

## `result` Image URLs

```sparql
PREFIX up: <http://purl.uniprot.org/core/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?tax ?up_uri ?id_uri ?image
WHERE {
  VALUES ?tax { "{{params.tax}}" }   ### SPARQList Ver. 2018-02-07 以降では params 不要の {{tax}}
  VALUES ?up_uri { <http://purl.uniprot.org/taxonomy/{{params.tax}}> }
  VALUES ?id_uri { <http://identifiers.org/taxonomy/{{params.tax}}> }
  ?up_uri foaf:depiction ?image
}
```

## Output

```javascript
({
  json({result}) {
    return result.results.bindings;
  },
  text({result}) {
    // return result.results.bindings.map(function(row) {
	// return result.results.bindings.map((row) => {  // same as above
	// return result.results.bindings.map(row => {    // same as above
	//   return row.image.value;
	// }).join("\n");
    return result.results.bindings.map(row => row.image.value).join("\n");  // same as above
  }
})
```

このようなファイルを repository ディレクトリ以下に置くことでファイル名を API 名として提供できる。 起動時に指定した ADMIN_PASSWORD で Login すると、ウェブブラウザ上でも API を作成したり編集したりできる。

  • ドキュメントは自由に記述可能
  • 最初の # 行が API の名前になる
  • ## Parameters に `hoge` のようにクオートすることで引数の変数名を指定
    • 変数の説明は自由に記述可能
    • デフォルト値はインデントして default: に続けて記載
    • 他に examples: などを追記することを推奨
  • ## Endpoint にエンドポイントの URL を記述
  • 続く ## セクションは、`foo` などで結果を受け取る変数名を指定、説明文は自由に記述可能
    • コードは ```sparql か ```javascript のブロックで記載
  • 最後のセクションの戻り値が API の戻り値となる
    • 最後のセクションが ```sparql の場合、ユーザからの Accept ヘッダがそのまま渡されるため、SELECT 以外の SPARQL に使える
    • 最後のセクションが ```javascript の場合、json() や text() などの関数を並べることで content negotiation する API に拡張できる → この場合 API の拡張子に .json や .text をつけることでも呼び出せるようになる。

fetch

  • 2018-02-20 ver.から javascript 内で "fetch" が使えるようになった
  • async, await を使って、SPARQLis や他の API、web ページなどが呼べる
    • SPARQL の条件分岐やループができる。SPARQList の再帰もできる
  • method: や body: や header: は API 依存
    • SPARQList は 'GET' か 'POST, Content-Type: application/x-www-form-urlencoded'
    • multipart/form-data の POST には未対応みたいです
```javascript
async ({var1, var2})=>{
    const options = {
      method: 'POST',
      body: "key=" + encodeURIComponent(value),
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    };

    try{
      var res = await fetch('http://example.org/rest/api/hoge', options).then(res=>res.json());
      return res;
    }catch(error){
      console.log(error);
    }
};
```
  • offset, limit で分轄して投げる SPARQList
    • virtuoso:ResultSetMaxRows を超えて取れるけど MaxSortedTopRows を超えてはソート出来ないのであまり意味ないかも
    • sparql 部分は別の SPARQList にする
    • loop 数ほぼ同時に endpoint を叩くので攻撃とみなされる可能性もある
    • Array.prototype.push.apply は入れ物になる方が大きくなりすぎるとブラウザによってはスタックオーバーフローする場合もある。
      • Firefox だと後者が大きい場合には問題なかったので、結合順を変えると回避できるかも
## Parameters

* `limit`
  * default: 100000

## `loop`

```javascript
async ({hoge, limit})=>{
  var options = {
    method: 'POST',
    body: "hoge=" + hoge, //適当に
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/x-www-form-urlencoded'
    }
  }
  var url = 'http://example.spaqrlist/rest/api/fuga'; // 行数を返す SPARQlist、多めで良い
  var count = await fetch(url, options).then(res=>res.json()).then(res=>res.results.bindings[0].count.value);
  var loop = Math.ceil(parseInt(count) / parseInt(limit));
  var res = [];
  var url = 'http://example.spaqrlist/rest/api/hoge'; //  limit ずつ行を取ってくる SPARQlist。PARQLは要order
  for(var i = 0; i < loop; i++){
    var offset = parseInt(limit) * i;
    options.body = "limit=" + limit + "&offset=" + offset; // offset と limit を渡す
    res[i] = fetch(url, options).then(res=>res.json());
  }
  var data = Promise.all(res); // SPARQL の結果が全部帰ってきたら
  return data.then(function(res){
    var sum = res[0];
    for(var i = 1; i < loop; i++){   
      Array.prototype.push.apply(sum.results.bindings, res[i].results.bindings); // スタックオーバーフローしないかどうか未確認
    }
    return sum;
  });
};
```

# `return`

```javascript
({
  json({recurse}){ // json
    return recurse;
  },
  text({recurse}){ // tsv
    var vars = recurse.head.vars;
    var list = recurse.results.bindings;
    var text = vars.join("\t") + "\n";
    for(var i = 0; i < list.length; i++){
      var values = [];
      for(var j = 0; j < vars.length; j++){
        var val = ""; 
        if(list[i][vars[j]]) val = list[i][vars[j]].value;
        if(val.match(/^\".+\"$/)) val = val.match(/^\"(.+)\"$/)[1];
        values.push(val);
      }
      text += values.join("\t") + "\n";
    }
    return text;
  }
})
```
  • ただし、SPARQList 内でオブジェクトが大きくなりすぎるとエラーになるもよう

Dockerfile

SPARQLthon55 で SPARQList の Dockerfile を作りました。

% docker build -t sparqlist:v1.0 .
% docker run -d -p 80:3000 sparqlist:v1.0
a1ab8042c9a83b0a0e95a7c0b02c3a13e9ce460ca4aed93d59918f17d2bf533c

http://localhost/sparqlist で見れるはずです。デプロイ例 → http://ep.dbcls.jp/sparqlist/

個人用ツール