Apollo Connectorsをサクッと動かしてみる

## はじめに
取り組むApollo Tutorialを間違えてしまい、Apollo Connectorsを学んでしまいました。
間違えて終わりだと悲しいので記事を投稿することで供養とします。

## 本記事の内容
- Apollo Connectorsについて
- Apollo Connectorsを動かす
- RESTのエンドポイントを叩いてみる

## Apollo Connectorsについて
Apollo Connectorsは、Apollo GraphOSの一機能として、既存のREST APIやGraphQL APIを簡単にGraphQLサブグラフとして統合できる仕組みです。

GraphQLを使いたいけど、既存のREST APIをすぐにGraphQLに置き換えるのは負担が大きい場合があります。Apollo Connectorsを活用することで、RESTのエンドポイントにそのままGraphQLでリクエストを送ることができる。

この仕組みによって、既存のAPIを活かしながら、段階的にGraphQLを導入することができます。

https://www.apollographql.com/docs/graphos/schema-design/connectors

## Apollo Connectorsを試すまで
以下ほぼ[公式チュートリアル](https://www.apollographql.com/tutorials/connectors-intro-rest)の内容なので、詳細を確認したい方は公式チュートリアルからどうぞ

### Apollo GraphOSアカウントを用意
[アカウントを作成](https://studio.apollographql.com/signup?referrer=odyssey&amp;_gl=1*1n1pjm8*_gcl_au*MTM4Mzc1NTA2Ny4xNzQ1NTQyOTE5)
### Roverのインストール
- Linux / Mac
    ```shell
    $ curl -sSL https://rover.apollo.dev/nix/latest | sh
    ```
- Windows
    ```shell
    $ iwr 'https://rover.apollo.dev/win/latest' | iex
    ```
### API Keyを取得する
任意の名前をAPIにつけて発行する。
##### 新規の組織の場合
![スクリーンショット 2025-04-25 10.15.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655193/42fbfa28-e308-4270-91fa-0c26216489f4.png)
##### 既存のGraphがある場合
Personal Setting > API Keys > Create API Key
![スクリーンショット 2025-04-25 10.55.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655193/449882e9-c575-4a0d-904d-d94687bb3d82.png)

#### roverを認証する
先ほどのAPI Keyを使って以下を実行する。
```rover config auth```の後にAPI Keyの入力を求められる。
```shell
$ rover config auth
$ rover config whoami
```

### プロジェクトを作る
作業ディレクトリ下で以下のコマンドを実行。
```shell
$ rover init
```

すると、いくつか質問がされます。
- Select option
    - Create a new graph
- Select use case
    - Start a graph with one or more REST APIs
- Name your graph
    - 任意の名前
- Confirm or modify graph ID
    - そのまま確定

```y```を入力してプロジェクトを作成してください。

この時、```APOLLO_KEY=<YOUR_APOLLO_KEY> rover dev --graph-ref <YOUR_GRAPH_REF> --supergraph-config supergraph.yaml```と表示されます。
後ほど使用するため、コピーしておきます。

### サンドボックスを実行する
- Linux/Mac
    先ほどコピーした以下をそのまま実行して動作を確認します。
    ```
    $ APOLLO_KEY=<YOUR_APOLLO_KEY> rover dev --graph-ref <YOUR_GRAPH_REF> --supergraph-config supergraph.yaml
    ```
- Windows
    コピーしたコマンドを以下のように書き直して実行してください。
    ```
    $ $env:APOLLO_KEY = "<YOUR_APOLLO_KEY>"; rover dev --graph-ref <YOUR_GRAPH_REF> --supergraph-config supergraph.yaml
    ```

### クエリを試してみる
```http://localhost:4000```にアクセスして、以下のクエリを実行してください。
```graphql
query ExampleQuery {
  products {
    id
    name
    description
  }
}
```

以下のようなデータが取得できれば成功です。
![スクリーンショット 2025-04-25 10.49.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655193/d69e4656-b726-436d-a8c7-3ce66b52332d.png)

## RESTのエンドポイントを叩いてみる
では実際に、RESTのエンドポイントをGraphQLで叩く例を試してみましょう。
今回はQiita APIからユーザー情報とユーザーが投稿した記事を一括で取得できるようにします。

### 準備

1. ```qiita.graphql```ファイルを作成
2. supergraph.yamlを以下のように変更
    ```yaml
    subgraphs:
      products:
        routing_url: http://ignore
        schema:
          file: products.graphql
      qiita:
        routing_url: http://ignore
        schema:
          file: qiita.graphql
    federation_version: =2.10.0
    ```

### 全体
```qiita.graphql
extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.10", import: ["@key"])
  @link(
    url: "https://specs.apollo.dev/connect/v0.1"
    import: ["@source", "@connect"]
  )
  @source(
    name: "qiita",
    http: { baseURL: "https://qiita.com/api/v2" }
  )

type Query {
  "A curated array of listings to feature on the homepage"
  qiitaUsers: [User!]!
    @connect(
      source: "qiita"
      http: { GET: "/users" }
      selection: """
        id
        name
        description
        organization
      """
    )

  "A specific listing"
  user(id: ID!): User
    @connect(
      source: "qiita"
      http: { GET: "/users/{$args.id}" }
      selection: """
        id
        name
        description
        organization
      """
      entity: true
    )
    
}

type User {
  "ユーザーID"
  id: ID!
  "ユーザー名"
  name: String
  "自己紹介文"
  description: String
  "所属している組織名"
  organization: String

  items: [Item!]!
    @connect(
      source: "qiita"
      http: { GET: "/users/{$this.id}/items" }
      selection: """
        id
        title
        url
        created_at
        updated_at
      """
    )
}

type Item {
  "記事ID"
  id: ID!
  "記事のタイトル"
  title: String!
  "記事のURL"
  url: String!
  "記事の作成日時"
  created_at: String!
  "記事の更新日時"
  updated_at: String!
}
```

### スキーマ
ここでは、GraphQLスキーマを拡張し、Qiita APIとの接続情報を定義しています。
- ＠link：Apollo FederationやConnectorsの仕様をスキーマに読み込みます。
- ＠source：Qiitaという名前でREST APIエンドポイントを登録します（baseURL）。

```
extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.10", import: ["@key"])
  @link(
    url: "https://specs.apollo.dev/connect/v0.1"
    import: ["@source", "@connect"]
  )
  @source(
    name: "qiita",
    http: { baseURL: "https://qiita.com/api/v2" }
  )
```

## Query定義
Qiitaの各エンドポイントをGraphQLのクエリとして定義します。
- qiitaUsers: Qiitaのユーザー一覧 (GET /users) を取得するクエリです。
- user(id: ID!): 特定ユーザーの情報を取得します。

```
type Query {
  qiitaUsers: [User!]!
    @connect(
      source: "qiita"
      http: { GET: "/users" }
      selection: """
        id
        name
        description
        organization
      """
    )

  user(id: ID!): User
    @connect(
      source: "qiita"
      http: { GET: "/users/{$args.id}" }
      selection: """
        id
        name
        description
        organization
      """
      entity: true
    )
}
```

### レスポンスデータの構造を定義
- User: Qiitaのユーザー情報。さらに items フィールドで、そのユーザーの投稿一覧も取得できます。
- ＠connect の {$this.id} により、User型インスタンスの id を使って動的にエンドポイントを変えて取得しています。
```
type User {
  id: ID!
  name: String
  description: String
  organization: String

  items: [Item!]!
    @connect(
      source: "qiita"
      http: { GET: "/users/{$this.id}/items" }
      selection: """
        id
        title
        url
        created_at
        updated_at
      """
    )
}
```
## 参考
https://www.apollographql.com/docs/graphos/schema-design/connectors

https://www.apollographql.com/tutorials/connectors-intro-rest

https://qiita.com/api/v2/docs

## 最後に
ミスから学び始めた技術でしたが、やってみると可能性を感じる技術でした。
GraphQLに祝福あれ。