[Oracle Cloud] GraphQL で Oracle Content Management のデータを取得する（３）


# はじめに

この記事は、以下の記事の続きです

**その１**

https://qiita.com/nakasato310/items/b160760dff00c5a53ca2

**その２**

https://qiita.com/nakasato310/items/d69952933a85d11543a5

過去2回の記事では、Oracle Content Management(以降OCM)に内蔵されるGraphQLエクスプローラ(GraphQL IDE)からアセット情報を取得する方法を紹介しました。

3回目となる今回は、GraphQLエクスプローラではなく、クライアントアプリケーションから OCM のアセット情報を取得する方法を紹介します

:::note info
この記事は、2021年12月時点でのOCMの最新バージョン(21.12.1)を元に作成されてます
:::

# 実現したいこと

+ OCMをHeadless CMSとして利用できるように構成します
+ クライアント・アプリケーションを作成します。今回は**Apollo Clinet(React)**のチュートリアルを利用します
+ クライアント・アプリケーションからOCMで作成・公開したアセット（コンテンツ・アイテム）の情報をGraphQLで取得・表示するように、クライアント・アプリケーションを変更します

  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120110/87496f92-d607-4351-4a89-c3bf9b4aec5f.png)


# 1. OCM - Starter Edition 環境の準備

### 1.1 インスタンス作成とアセット登録・公開

OCM - Starter Edition とは、**Oracle Cloud Always Free（無償かつ期間の制限無し）**で利用できるOCMの機能限定版です。

以下の記事を参考に、OCM - Starter Edition環境を作成します。

https://qiita.com/nakasato310/items/9457a61d9d27db6ce4f0

最終的には、以下のような形でアセット・リポジトリ内に2件のアセット（画像とコンテンツ・アイテム）が登録された状態になります

![image.png](https://camo.qiitausercontent.com/f048d95722cc32310a89f210aeec8508a4e2c7f2/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3132303131302f34396435363766322d613038382d663836662d643139362d6463376139316464346265352e706e67)

コンテンツ・アイテムは、`sampleNewsType`というコンテンツ・タイプより作成されます。sampleNewsTypeは、`タイトル(title)`、`メイン画像(image)`、`ニュース本文(body)`の3つのデータ・フィールド(属性)から構成されます。

![image.png](https://camo.qiitausercontent.com/d963951408b749f75486587b90552b98a3109e28/68747470733a2f2f6f7261636c652d6a6170616e2e6769746875622e696f2f6f63697475746f7269616c732f636f6e74656e742d6d616e6167656d656e742f34315f61737365745f686561646c6573732f3032302e6a7067)

### 1.2 チャネル・トークンの確認

このアセットリポジトリには、`sampleChannel`という公開チャネルが設定されます。React+Apollo Clientからアセットを参照する際に、この`sampleChannel`の**チャネル・トークン**を利用します

チャネル・トークンは、OCMのUIから`ADMINISTRATION:コンテンツ`→`チャネルのパブリッシュ`→`sampleChannel`→`右上のサイドパネルボタン`→`API`より確認できます。この**チャネル・トークン**をメモします

![image.png](https://camo.qiitausercontent.com/969bcfa200f491793a26e929186144b590142f12/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3132303131302f35343935373935382d633734392d383336622d383466332d3838366430373034366335342e706e67)


# 2. クライアント・アプリケーションの開発

1.で作成したOCMに対してGraphQLのクエリを発行するクライアント・アプリケーションを作成します。今回は、**React+Apollo Client**の環境を準備します。

以下のApollo Client(React)の公式チュートリアルを実施します

https://www.apollographql.com/docs/react/get-started/

### 2.1 事前準備

+ `Create-React-App`を実行し、新しいプロジェクトを作成します 

```terminal
npx create-react-app my-app
cd my-app
npm start
```

> [メモ] 私の場合`npm start`がエラーで実行できなかったので、プロジェクトフォルダ(ここではmy-appフォルダ)の直下に`.env`ファイルを作成し、`SKIP_PREFLIGHT_CHECK=true`を追加することで、エラーを一旦回避しました

```config:.env
SKIP_PREFLIGHT_CHECK=true
```

+ 必要なパッケージをインストールします

```terminal
npm install @apollo/client graphql
```

### 2.2 React+Apollo Clientアプリケーションの開発

作成したReactアプリケーションに、Apollo Clientを組み込みます。具体的には、**2. Initialize ApolloClient**以降のチュートリアルを最後まで実施します。

https://www.apollographql.com/docs/react/get-started/#2-initialize-apolloclient

最終的に、`src/index.js` は以下のコードとなります

```javascript:index.js
import React from 'react';
import { render } from 'react-dom';
import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider,
  useQuery,
  gql
} from "@apollo/client";

const client = new ApolloClient({
  uri: 'https://48p1r2roz4.sse.codesandbox.io',
  cache: new InMemoryCache()
});

const EXCHANGE_RATES = gql`
  query GetExchangeRates {
    rates(currency: "USD") {
      currency
      rate
    }
  }
`;

function ExchangeRates() {
  const { loading, error, data } = useQuery(EXCHANGE_RATES);
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return data.rates.map(({ currency, rate }) => (
    <div key={currency}>
      <p>
        {currency}: {rate}
      </p>
    </div>
  ));
}

function App() {
  return (
    <div>
      <h2>My first Apollo app 🚀</h2>
      <ExchangeRates />
    </div>
  );
}

render(

  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root'),
);
```

実行すると、以下のWebページが表示され、GraphQLクエリで取得したデータが表示されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120110/3fb18e27-5f90-56e2-a4bb-be923078d028.png)

#### 説明

index.jsに書かれているコードの詳細は、以下Apollo Client(React)のチュートリアルをご確認ください

https://www.apollographql.com/docs/react/get-started/


# 3. OCMのアセット情報を表示するようにindex.jsを変更する

### 3.1 GraphQLサーバーの接続先をOCMに変更する

```diff_javascript:index.js
- uri: 'https://48p1r2roz4.sse.codesandbox.io',
+ uri: 'https://<ocminstance>-<tenancy>.cec.ocp.oraclecloud.com/content/published/api/v1.1/graphql',
```

#### 説明

OCMのGraphQLのエンドポイントは以下の通りです

+ `https://<ocminstance>-<tenancy>.cec.ocp.oraclecloud.com/content/published/api/v1.1/graphql`
+ `<ocminstance>` は**OCMインスタンス名** を入力
+ `<tenancy>` は **テナンシー名** を入力


### 3.2 OCMからsampleNewsTypeコンテンツ・タイプのアセット一覧を取得するクエリに修正

```diff_javascript:index.js
- const EXCHANGE_RATES = gql`
-  query GetExchangeRates {
-   rates(currency: "USD") {
-     currency
-     rate
-   }
-  }
-  `;
+ const ITEMS_FROMOCM = gql`
+  query GetItemsFromOCM {
+   getItems(channelToken: "<channelToken>", 
+     filter: {type: {op: EQUALS, value: "sampleNewsType"}}
+   ) {
+     items {
+       id
+       name
+       slug
+     }
+   }
+  }
+ `;
```

#### 説明

+ GraphQLクエリ名を変更（`EXCHANGE_RATES` → `ITEMS_FROMOCM`）
+ `getItems()`クエリを利用し、アセット・タイプ`sampleNewsType`のコンテンツ・アイテムを取得
+ `channelToken:`には、1.2項で確認したチャネルトークンを設定
+ `filter:`には、アセット・タイプ=sampleNewsTypeを設定
+ 取得するフィールドは`id`, `name`, `slug` の3項目を設定
+ getItems()クエリの使いかたは、以下のQiita記事で紹介してます。ご確認ください
    - [[Oracle Cloud] GraphQL で Oracle Content Management のデータを取得する（２）](https://qiita.com/nakasato310/items/d69952933a85d11543a5)


### 3.3 getItems() で取得したデータを表示するように既存コンポーネントを変更

```diff_javascript:index.js
- function ExchangeRates() {
-  const { loading, error, data } = useQuery(EXCHANGE_RATES);
-  if (loading) return <p>Loading...</p>;
-  if (error) return <p>Error :(</p>;
-
-  return data.rates.map(({ currency, rate }) => (
-   <div key={currency}>
-     <p>
-       {currency}: {rate}
-     </p>
-   </div>
-  ));
- }
+ function ItemsFromOCM() {
+  const { loading, error, data } = useQuery(ITEMS_FROMOCM);
+  if (loading) return <p>Loading...</p>;
+  if (error) return <p>Error :(</p>;
+
+  return data.getItems.items.map(({ id, name, slug }) => (
+   <div key={id}>
+      <p>
+        {id} : {name} : {slug}
+      </p>
+    </div>
+  ));
+ }
```

#### 説明

+ コンポーネント名を変更（`ExchangeRates` → `ItemsFromOCM`）
+ `useQuery()`で、3.3項で変更したGraphQLクエリ`ITEMS_FROMOCM`をパス
+ 取得したアセット情報は`data`に含まれます


### 3.4 既存のAppコンポーネントに``<ItemsFromOCM>``コンポーネントを追加

```diff_javascript:index.js
-     <div>
-       <h2>My first Apollo app 🚀</h2>
-       <ExchangeRates />
-     </div>
+     <div>
+       <h2>My first Apollo app 🚀</h2>
+       <ItemsFromOCM />
+     </div>
```


# 4. 確認

クライアント・アプリケーションを起動し、OCMからアセット情報が取得できるか？を確認します

```command
npm start
```

起動すると、以下のようにWebページが表示され、OCMから取得した`id`,`name`,`slug`のアセット情報が表示されます（ここでは2件のコンテンツ・アイテムが表示）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120110/f0911a8a-8a24-11c4-146b-845dcd6f1feb.png)

OCM環境で`sampleNewsType`のコンテンツアイテムを新規に1件作成し、`sampleChannel`に対して公開します(ここでは`sample news content 003`を新規作成・公開)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120110/83eacc90-5b7b-d81a-9bec-1e046c2d217d.png)

ブラウザをリロードすると、先ほど新規作成したコンテンツ・アイテム`sample news content 003`が1件追加されることが確認できます（ここでは3件のコンテンツ・アイテムが表示）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120110/280fbb6f-2da5-2912-50be-1f9a7f521e22.png)


# まとめ

この記事では、**React+Apollo Client**で開発したクライアントアプリケーションから、OCMのアセットリポジトリで管理・公開されるアセットを **GraphQL** で取得・表示できることを確認しました。

この記事を作成する際に参考にした記事やドキュメントを最後にリンクします


+ **OCM製品ドキュメント**
    + [GraphQL Support in Oracle Content Management](https://docs.oracle.com/en/cloud/paas/content-cloud/solutions/graphql-support-oracle-content-management.html#GUID-E7B5E5E6-94B3-41BC-A1E7-6EB8327A3D25)
    + [Oracle Content Management - Samples](https://docs.oracle.com/en/cloud/paas/content-cloud/samples.html) 

+ **Qiita記事**
    + [Apollo Client で始める GraphQL](https://qiita.com/sotszk/items/b3c63c2bf08aca61805e)


##（参考）OCMの製品ドキュメント

+ [Oracle Content Management 製品ドキュメント（英語）](https://docs.oracle.com/en/cloud/paas/content-cloud/books.html)
+ [Oracle Content Management 製品ドキュメント（日本語翻訳版）](https://docs.oracle.com/cloud/help/ja/content-cloud/index.htm)  
  `製品ドキュメントの英語原本と日本語翻訳版です。翻訳されるまでに時差がありますので、最新情報の確認は 英語版のドキュメントをご利用ください`