SPARQList
提供:TogoWiki
Uki moriya (トーク | 投稿記録) |
細 (→使い方: typo修正) |
||
| 134行: | 134行: | ||
* 続く ## セクションは、`foo` などで結果を受け取る変数名を指定、説明文は自由に記述可能 | * 続く ## セクションは、`foo` などで結果を受け取る変数名を指定、説明文は自由に記述可能 | ||
** コードは ```sparql か ```javascript のブロックで記載 | ** コードは ```sparql か ```javascript のブロックで記載 | ||
| - | ** sparql コード内では | + | ** sparql コード内では handlebars 表記が使用可能 |
*** { {hoge }}, { {foo.bar }} で変数の埋め込みの他、{{#if hoge}}, {{#unless fuga}} 条件文や {{#each array}} ループ処理など | *** { {hoge }}, { {foo.bar }} で変数の埋め込みの他、{{#if hoge}}, {{#unless fuga}} 条件文や {{#each array}} ループ処理など | ||
* 最後のセクションの戻り値が API の戻り値となる | * 最後のセクションの戻り値が API の戻り値となる | ||
| 259行: | 259行: | ||
</pre> | </pre> | ||
* ただし、SPARQList 内でオブジェクトが大きくなりすぎるとエラーになるもよう | * ただし、SPARQList 内でオブジェクトが大きくなりすぎるとエラーになるもよう | ||
| - | |||
== Dockerfile == | == Dockerfile == | ||
2023年2月21日 (火) 01:00時点における最新版
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, ...
* `subdomain`
* default: dev
## Endpoint
http://{{subdomain}}.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
},
html: hbs(`
<ul>
{{#each result.results.bindings as |row|}}
<li>{{row.image.value}}</li>
{{/each}}
</ul>
`)
})
```
このようなファイルを repository ディレクトリ以下に置くことでファイル名を API 名として提供できる。 起動時に指定した ADMIN_PASSWORD で Login すると、ウェブブラウザ上でも API を作成したり編集したりできる。
- ドキュメントは自由に記述可能
- 最初の # 行が API の名前になる
- ## Parameters に `hoge` のようにクオートすることで引数の変数名を指定
- 変数の説明は自由に記述可能
- デフォルト値はインデントして default: に続けて記載
- 他に examples: などを追記することを推奨
- ## Endpoint にエンドポイントの URL を記述
- 続く ## セクションは、`foo` などで結果を受け取る変数名を指定、説明文は自由に記述可能
- コードは ```sparql か ```javascript のブロックで記載
- sparql コード内では handlebars 表記が使用可能
- { {hoge }}, { {foo.bar }} で変数の埋め込みの他、{{#if hoge}}, {{#unless fuga}} 条件文や {{#each array}} ループ処理など
- 最後のセクションの戻り値が API の戻り値となる
- 最後のセクションが ```sparql の場合、ユーザからの Accept ヘッダがそのまま渡されるため、SELECT 以外の SPARQL に使える
- 最後のセクションが ```javascript の場合、json() や text() などの関数を並べることで content negotiation する API に拡張できる → この場合 API の拡張子に .json や .text をつけることでも呼び出せるようになる。
- html: hbs() で handlbars で HTML 出力サンプルを記述、表示できる (2019-03-18以降のVer.)
- 中間のセクションの JavaScript の書き方
```javascript
({var1, var2}) => {
... code ...
return json;
};
```
または
```javascript
function({var1, var2}){
... code ...
return json;
}();
```
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 は入れ物になる方が大きくなりすぎるとスタックオーバーフローする場合もある。
## 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/
Method
- POST でも form data を string を渡せるが、json には未対応
curl -X POST -d 'key1=value1&key2=value2&key3=value3' https://sparqlist
Heap size limit
- Node.js が使っている V8 JavaScript エンジンにヒープサイズリミットがあり、大規模に使うとリミットまで使い切って、応答が詰まる場合がある
確認方法 (MB) node -e 'console.log(v8.getHeapStatistics().heap_size_limit/1024/1024)' 変更例(起動時の例)(MB) NODE_OPTIONS="--max-old-space-size=8192" npm start
記述支援ツール
- SPARQList support
- SPARQL, JavaScript を一段階ずつ処理しながら、SPARQLet 開発ができます