情報銀行のプラットフォームとして利用できるかもしれないPersonium（PDS） を検証してみる ８ ＜APIでODataを触ってみる＞

##[＜APIでWebDavを触ってみる＞](https://qiita.com/takky0330/items/42febbf90de2986bb452)で WebDav についての理解は深められたので、次は当然 OData に進めましょう。

ODataとは正式名称は”Open Data Protocol”で「RESTfulなWebAPI（Webサービス）プロトコル」のことで、Microsoft主導で策定されたようです。
Personium でのDBエンジンは Elasticsearch を採用しており、インターフェスは OData という構図になっています。

インターフェースがRESTfulなWebAPIである点と、通常RDBとして採用されるOracleやMySQLなどとも若干差異がある部分もあり、その辺についても把握できることを目指したいと思います。

##１．環境の確認

セルやボックスは、[＜APIでWebDavを触ってみる＞](https://qiita.com/takky0330/items/42febbf90de2986bb452)で利用したものをそのまま使うこととし、以下のような環境で試してみましょう。

| 項目 | 値 | 備考 |
|:--|:--|:--|
| ユニット | https://personium.takky.org |
| セル | usercell |
| ボックス | userbox |
| アカウント | user |
| ロール | userrole |
| コレクション（ACL） | ODataContents （read,write） | RDBでのデータベース |
| エンティティタイプ | profile | RDBでのテーブル |


##２．管理者権限でのODataのCollection（データベース）の作成

まずは恒例の… unitadmin のトークンを取得しましょう。

```
$ curl "https://personium.takky.org/unitadmin/__token" \
-X POST -i \
-d "grant_type=password&username={{unitAdminUser}}&password={{unitAdminPassword}}&p_target=https://personium.takky.org/" \
-H "Content-Type: application/x-www-form-urlencoded"

HTTP/1.1 200 
Date: Wed, 20 Mar 2019 05:28:50 GMT
Content-Type: application/json
Content-Length: 4378
Connection: keep-alive
Location: https://personium.takky.org/__token
X-Personium-Version: 1.7.4
Server: Personium

{
　"access_token":"{{unitAdminToken}}",
　"refresh_token_expires_in":86400,
　"refresh_token":"{{refreshToken}}",
　"p_target":"https:\/\/personium.takky.org\/",
　"token_type":"Bearer",
　"expires_in":3600
}
```

次は、コレクション（データベース）の作成です。
uriはWebDavと同様に、curl "https://personium.takky.org/{{cell}}/{{box}}/{{collection}}" のようにしましょう。

bodyには以下のようなXMLを記載する必要があるのですが、コレクションを作成する場合はこのままで良いようなので、そのまま利用します。
（リソースタイプは＂odata＂の＂collection＂ですよ。ということが表現されているようです。WebDavの時は＂odata＂の所に＂WebDav＂とは指定しなかったですが… ここに＂WebDav＂と＂odata＂の違いがありそうですね）
```<D:mkcol xmlns:D=\"DAV:\" xmlns:p=\"urn:x-personium:xmlns\"><D:set><D:prop><D:resourcetype><D:collection/><p:odata/></D:resourcetype></D:prop></D:set></D:mkcol>```


```
$ curl "https://personium.takky.org/usercell/userbox/ODataContents" -X MKCOL -i \
-d "<?xml version=\"1.0\" encoding=\"utf-8\"?><D:mkcol xmlns:D=\"DAV:\" xmlns:p=\"urn:x-personium:xmlns\"><D:set><D:prop><D:resourcetype><D:collection/><p:odata/></D:resourcetype></D:prop></D:set></D:mkcol>" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 201 
Date: Wed, 20 Mar 2019 05:32:47 GMT
Content-Length: 0
Connection: keep-alive
ETag: "1-1553059967130"
X-Personium-Version: 1.7.4
Server: Personium
```

レスポンスコードが200番台なので、成功したようなのですが… ほんまかね？？

確認してみましょう！
確認の方法も、WebDavと全く同じですね。

```
$ curl "https://personium.takky.org/usercell/userbox/ODataContents" \
-X PROPFIND -i \
-H 'Depth:1' \
-d '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 207 
Date: Wed, 20 Mar 2019 05:40:59 GMT
Content-Type: application/xml
Content-Length: 709
Connection: keep-alive
ETag: "1-1553059967130"
X-Personium-Version: 1.7.4
Server: Personium

<multistatus xmlns="DAV:">
    <response>
        <href>https://personium.takky.org/usercell/userbox/ODataContents</href>
        <propstat>
            <prop>
                <creationdate>2019-03-20T05:32:47.130+0000</creationdate>
                <getlastmodified>Wed, 20 Mar 2019 05:32:47 GMT</getlastmodified>
                <resourcetype>
                    <collection/>
                    <p:odata xmlns:p="urn:x-personium:xmlns"/>
                </resourcetype>
                <acl xml:base="https://personium.takky.org/usercell/__role/userbox/" xmlns:p="urn:x-personium:xmlns"/>
            </prop>
            <status>HTTP/1.1 200 OK</status>
        </propstat>
    </response>
</multistatus>
```

大丈夫そうです。
念のため、ユニットマネージャでも確認。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/352554/510f7ae0-60c8-c476-25f7-abbba752fc02.png)

ちゃんとできてますね！！ OKです。


##３．管理者権限でのODataのEntityType（テーブル）の作成

次はテーブルの作成になりますね。
ODataではテーブルではなく EntityType と呼ばれているようです。
しかもこのテーブル作成時には、RDBでいうカラム（Entity）などは設定しなくても良いようです。
まずは、この EntityType を作成しましょう。

```
$ curl "https://pds.takky.org/OData/ODataBox/testOData/\$metadata/EntityType" \
-X POST -i \
-d '{ "Name":"profile"}' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 201 
Date: Wed, 20 Mar 2019 05:59:25 GMT
Content-Type: application/json
Content-Length: 302
Connection: keep-alive
Location: https://personium.takky.org/usercell/userbox/ODataContents/$metadata/EntityType('profile')
DataServiceVersion: 2.0
ETag: W/"1-1553061565244"
X-Personium-Version: 1.7.4
Server: Personium

{
  "d":{
    "results":{
      "__metadata":{
        "uri":"https:\/\/personium.takky.org\/usercell\/userbox\/ODataContents\/$metadata\/EntityType('profile')",
        "etag":"W\/\"1-1553061565244\"",
        "type":"ODataSvcSchema.EntityType"
      },
      "Name":"profile","__published":"\/Date(1553061565244)\/",
      "__updated":"\/Date(1553061565244)\/"
    }
  }
}
```

これもレスポンスコードが200番台で返ってきました！
こちらも念のため、ユニットマネージャで確認しておきましょう…

![image.png](https://qiita-image-store.s3.amazonaws.com/0/352554/6fb67f0d-246b-42c9-d0e3-8cebdaab28e1.png)

＂ODataContents＂コレクションの配下に、＂profile＂が存在しています。
OKですね！！

コマンドでは確認すれば良いのでしょう？
以下のように＂GET＂で確認できるようで、WebDavの取得方法（＂PROPFIND＂）ではないみたいですね。

```
$ curl "https://personium.takky.org/usercell/userbox/ODataContents/\$metadata" \
-X GET -i \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 200 
Date: Wed, 20 Mar 2019 06:11:00 GMT
Content-Type: application/xml;charset=utf-8
Content-Length: 1084
Connection: keep-alive
DataServiceVersion: 1.0
X-Personium-Version: 1.7.4
Server: Personium

<?xml version="1.0" encoding="utf-8"?>
  <edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:p="urn:x-personium:xmlns">
    <edmx:DataServices m:DataServiceVersion="1.0">
      <Schema xmlns="http://schemas.microsoft.com/ado/2006/04/edm" Namespace="UserData">
        <EntityType Name="profile" OpenType="true">
          <Key>
            <PropertyRef Name="__id"></PropertyRef>
          </Key>
          <Property Name="__id" Type="Edm.String" Nullable="false" DefaultValue="UUID()" p:Format="regEx('^.{1,400}$')"></Property>
          <Property Name="__published" Type="Edm.DateTime" Nullable="false" DefaultValue="SYSUTCDATETIME()" Precision="3"></Property>
          <Property Name="__updated" Type="Edm.DateTime" Nullable="false" DefaultValue="SYSUTCDATETIME()" Precision="3"></Property>
        </EntityType>
        <EntityContainer Name="UserData" m:IsDefaultEntityContainer="true">
          <EntitySet Name="profile" EntityType="UserData.profile"></EntitySet>
        </EntityContainer>
      </Schema>
    </edmx:DataServices>
  </edmx:Edmx>
```

急にXMLでのレスポンスになりました…（びっくり！）
EntityTypeは「Name="profile"」です。正しいですね。
Key が「Name="\_\_id"」で、
Property として「Name="\_\_id"」「Name="\_\_published"」「Name="\_\_updated"」があるのでしょうか？？

こちらもユニットマネージャで確認してみましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/352554/1203fde7-4a7e-5a31-a6ae-7fabd82911cb.png)

おゃ… ［Schema］を開いてみると、Property には何もなく…「No properties added yet」とな？！
もしかすると上記の3つの値は、デフォルトで作成され、かつ、デフォルトで値が入力されるカラムなのかもね？？


[『OData Service Collection (OSC)の使い方』](https://personium.io/docs/ja/app-developer/using_odata.html) というドキュメントに記載がありました。
やはり、3つの項目（列）は自動で作成されるようです。大丈夫！！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/352554/9bc6280f-fa0b-661d-9773-6ab0fcd30ecb.png)


##４．管理者権限でのデータのストア

では満を持して… データを挿入してみましょう。

```
$ curl "https://personium.takky.org/usercell/userbox/ODataContents/profile" \
-X POST -i \
-d '{"name": "Takky"}' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 201 
Date: Wed, 20 Mar 2019 06:45:46 GMT
Content-Type: application/json
Content-Length: 344
Connection: keep-alive
Location: https://personium.takky.org/usercell/userbox/ODataContents/profile('d2f6a5c5c718401ab86c98a555e331f1')
DataServiceVersion: 2.0
ETag: W/"1-1553064346586"
X-Personium-Version: 1.7.4
Server: Personium

{
  "d":{
    "results":{
      "__metadata":{ 
        "uri":"https:\/\/personium.takky.org\/usercell\/userbox\/ODataContents\/profile('d2f6a5c5c718401ab86c98a555e331f1')",
        "etag":"W\/\"1-1553064346586\"",
        "type":"UserData.profile"
      },
      "__id":"d2f6a5c5c718401ab86c98a555e331f1",
      "__published":"\/Date(1553064346586)\/",
      "__updated":"\/Date(1553064346586)\/",
      "name":"Takky"
    }
  }
}
```

おぉ！ イケましたわぁ。
name列が作られ、＂Takky＂が設定されています。
そして想定通り、"\_\_id" "\_\_published" "\_\_updated"にも、値が入力されています。

ユニットマネージャでの確認でも、スキーマとして＂name＂が確認でき、実際のデータにも＂name＂列に＂Takky＂として1レコード挿入されています。完璧です！！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/352554/80a1a685-4c71-9b8b-dcbc-45d8a9b4c0dd.png)


##５．ユーザー権限でのスキーマの参照

では次に… ユーザー権限でODataのオブジェクトにアクセスしてみましょう。
当然、エラーになるんだと思います。

まずは、トークンの取得。

```
$ curl "https://personium.takky.org/usercell/__token" \
-X POST -i \
-d "grant_type=password&username={{userName}}&password={{userPassword}}" \
-H "Content-Type: application/x-www-form-urlencoded"

HTTP/1.1 200 
Date: Sun, 24 Mar 2019 01:49:13 GMT
Content-Type: application/json
Content-Length: 331
Connection: keep-alive
X-Personium-Version: 1.7.4
Server: Personium

{
  "access_token":"{{user_token}}",
  "refresh_token_expires_in":86400,
  "refresh_token":{{fefresh_token}}",
  "token_type":"Bearer",
  "expires_in":3600
}
```

では、ユーザー権限でアクセスしましょう。

```
$ curl "https://personium.takky.org/usercell/userbox/ODataContents/\$metadata" \
-X GET -i \
-H "Accept:application/json" -H "Authorization:Bearer {{user_token}}"

HTTP/1.1 403 
Date: Sun, 24 Mar 2019 02:02:05 GMT
Content-Type: application/json
Content-Length: 90
Connection: keep-alive
X-Personium-Version: 1.7.4
Server: Personium

{
  "code":"PR403-AU-0002",
  "message":{
    "lang":"en",
    "value":"Necessary privilege is lacking."
  }
}
```

当然、「権限が足りない」エラーですね。

では次に、[＜APIでWebDavを触ってみる＞](https://qiita.com/takky0330/items/42febbf90de2986bb452)で作成済みの、ユーザー（user）にひも付いているロール（userrole）にACL（read, write）を付与しましょう。

```
url 'https://personium.takky.org/usercell/userbox/ODataContents'  \
-X ACL -i \
-d '<D:acl xmlns:D="DAV:" xmlns:p="urn:x-personium:xmlns" xml:base="https://personium.takky.org/usercell/__role/userbox/"><D:ace><D:principal><D:href>userrole</D:href></D:principal><D:grant><D:privilege><p:read/></D:privilege><D:privilege><p:write/></D:privilege></D:grant></D:ace></D:acl>' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 200 
Date: Sun, 24 Mar 2019 02:14:04 GMT
Content-Length: 0
Connection: keep-alive
ETag: "2-1553059967130"
X-Personium-Version: 1.7.4
Server: Personium
```

ACLを付与したので、もう一度…

```
$ curl "https://personium.takky.org/usercell/userbox/ODataContents/\$metadata" \
-X GET -i \
-H "Accept:application/json" -H "Authorization:Bearer {{user_token}}"

HTTP/1.1 200 
Date: Sun, 24 Mar 2019 02:15:59 GMT
Content-Type: application/xml;charset=utf-8
Content-Length: 1172
Connection: keep-alive
DataServiceVersion: 1.0
X-Personium-Version: 1.7.4
Server: Personium

<?xml version="1.0" encoding="utf-8"?>
  <edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:p="urn:x-personium:xmlns">
    <edmx:DataServices m:DataServiceVersion="1.0">
      <Schema xmlns="http://schemas.microsoft.com/ado/2006/04/edm" Namespace="UserData">
        <EntityType Name="profile" OpenType="true">
          <Key>
            <PropertyRef Name="__id"></PropertyRef>
          </Key>
          <Property Name="__id" Type="Edm.String" Nullable="false" DefaultValue="UUID()" p:Format="regEx('^.{1,400}$')"></Property>
          <Property Name="__published" Type="Edm.DateTime" Nullable="false" DefaultValue="SYSUTCDATETIME()" Precision="3"></Property>
          <Property Name="__updated" Type="Edm.DateTime" Nullable="false" DefaultValue="SYSUTCDATETIME()" Precision="3"></Property>
          <Property Name="name" Type="Edm.String" Nullable="true" p:IsDeclared="false</Property>
        </EntityType>
        <EntityContainer Name="UserData" m:IsDefaultEntityContainer="true">
          <EntitySet Name="profile" EntityType="UserData.profile"></EntitySet>
        </EntityContainer>
      </Schema>
    </edmx:DataServices>
  </edmx:Edmx>
```

イケてますね！


##６．ユーザー権限でのデータのストア

ここでは、name列に＂USER＂のレコードを挿入しましょう。
これに成功すると、unitadmmin で挿入した＂Takky＂との２レコードになるはずです。

```
curl "https://personium.takky.org/usercell/userbox/ODataContents/profile" \
-X POST -i \
-d '{"name": "USER"}' \
-H "Accept:application/json" -H "Authorization:Bearer {{user_token}}"

HTTP/1.1 201 
Date: Sun, 24 Mar 2019 02:23:25 GMT
Content-Type: application/json
Content-Length: 343
Connection: keep-alive
Location: https://personium.takky.org/usercell/userbox/ODataContents/profile('471d31832e894809b5d18943dae3d20c')
DataServiceVersion: 2.0
ETag: W/"1-1553394205719"
X-Personium-Version: 1.7.4
Server: Personium

{
  "d":{
    "results":{
      "__metadata":{
        "uri":"https:\/\/personium.takky.org\/usercell\/userbox\/ODataContents\/profile('471d31832e894809b5d18943dae3d20c')",
        "etag":"W\/\"1-1553394205719\"",
         "type":"UserData.profile"
      },
      "__id":"471d31832e894809b5d18943dae3d20c",
      "__published":"\/Date(1553394205719)\/",
      "__updated":"\/Date(1553394205719)\/",
      "name":"USER"
    }
  }
}
```

##７．ユーザー権限でのデータの参照

では、実際に＂Takky＂と＂USER＂レコードがストアされているデータを参照（SELECT）してみましょう。

```
$ curl "https://personium.takky.org/usercell/userbox/ODataContents/profile" \
-X GET -i \
-H "Accept:application/json" -H "Authorization:Bearer {{user_token}}"

HTTP/1.1 200 
Date: Sun, 24 Mar 2019 02:43:13 GMT
Content-Type: application/json;charset=utf-8
Content-Length: 672
Connection: keep-alive
DataServiceVersion: 2.0
X-Personium-Version: 1.7.4
Server: Personium

{
  "d":{
    "results":[
      {
        "__metadata":{
          "uri":"https:\/\/personium.takky.org\/usercell\/userbox\/ODataContents\/profile('d2f6a5c5c718401ab86c98a555e331f1')",
          "etag":"W\/\"1-1553064346586\"",
          "type":"UserData.profile"
        },
        "__id":"d2f6a5c5c718401ab86c98a555e331f1",
        "__published":"\/Date(1553064346586)\/",
        "__updated":"\/Date(1553064346586)\/",
        "name":"Takky"
      },{
        "__metadata":{
          "uri":"https:\/\/personium.takky.org\/usercell\/userbox\/ODataContents\/profile('471d31832e894809b5d18943dae3d20c')",
          "etag":"W\/\"1-1553394205719\"",
          "type":"UserData.profile"
        },
        "__id":"471d31832e894809b5d18943dae3d20c",
        "__published":"\/Date(1553394205719)\/",
        "__updated":"\/Date(1553394205719)\/",
        "name":"USER"
      }
    ]
  }
}
```

profile テーブルに、これまでにストアした「Takky」「USER」が存在していることが確認できます。OKですね。


ついでにユニットマネジャーでも確認。
同様に、「Takky」「USER」が存在しています。
OK！！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/352554/bf9d8f90-12ae-2887-45fa-645c718561aa.png)

####ODataコレクション（テーブル）の作成と、レコードの登録・参照が完了です！

---

###最後に…

ODataとはインターフェスであり、実際のデータベースとしての機能は Elasticsearch が提供しています。Personium のデータベース機能を効果的に利用するためには、OData と Elasticsearchを把握することにより理解が深まるかと思います。

まぁでも全部を把握する必要もないと思いますので、[Personium API リファレンス](https://personium.io/docs/ja/apiref/current/000_Rest_API_Reference.html)内の以下のAPIを把握することになるでしょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/352554/60f6f460-d274-c41f-6632-5f1daa03ffa0.png)

CollectionやEntityType、EntitySet などをざっくり把握できれば、ほぼRDBと似た操作でデータを扱うことができるので、大いに活用したい機能ですね。



---

####メニュー
- [x] [１＜はじめに＞](https://qiita.com/takky0330/items/5352a820e5e59747218c)
- [x] [２＜Personiumに触れてみるには＞](https://qiita.com/takky0330/items/6e7e5686c8ab2a25f7e8)
- [x] [３＜Ansibleでインストールする＞](https://qiita.com/takky0330/items/19449b05e8b2775382d5)
- [x] [４＜ざっくりとPersoniumとは＞](https://qiita.com/takky0330/items/7781d0cb4ac879b65ab5)
- [x] [５＜APIでアクセスしてみる＞](https://qiita.com/takky0330/items/270a5c5386fd80d5d3c1)
- [x] [６＜VirtualBoxイメージでサクッと触る＞](https://qiita.com/takky0330/items/788ff75f675c9207ad6e)
- [x] [７＜APIでWebDavを触ってみる＞](https://qiita.com/takky0330/items/42febbf90de2986bb452)
- [x] [８＜APIでODataを触ってみる＞](https://qiita.com/takky0330/items/c1809ad5f3f7f85430ad)
- [x] [９＜APIでExtRoleを触ってみる＞](https://qiita.com/takky0330/items/74285b516e06fc00edad)
- [ ] １０＜セルとボックスについて理解する＞
- [ ] １１＜ホームアプリを触ってみる＞
- [ ] １２＜ユニットマネージャって便利じゃん＞
- [ ] １３＜テンプレートアプリってなんぞや＞
- [ ] １４＜自分のアプリケーション＞


- [x] [＜成功した手順＞ 新しいバージョン（1.7.9）の Personium を Ansibleでインストールする](https://qiita.com/takky0330/items/9598498f8dbb9681fc9b)
- [x] [＜失敗した手順＞ 新しいバージョン（1.7.9）の Personium を Ansibleでインストールする](https://qiita.com/takky0330/items/1706be1e23122ec2ac86)