type-graphqlの使い方

Node.js、Express、Angular、sequelizeを使ったWebシステムの開発に挑戦中です(MEANスタックに似てますが、データベースにPostgresを使っているので、PEANって事になるんでしょうね)

Angularから、Node.js+Expressにアクセスする方法を調べて見ると、RESTよりGraphqlの方が便利だという記事を読んだので、これを使ってみます。
全体的にTypeScriptで纏めたいので、type-graphqlを使う事にします。

# graphsql関連のインストール
graphsql、@types/graphql、type-graphsqlをインストールします。
> npm install graphql @types/graphql type-graphql --save

# tsconfig.jsonの変更
compilerOptionsに以下の行を追加します。

```json:tsconfig.json
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
```

compilerOptionsのtargetをes2016に変更します。

```json:tsconfig.json
"target": "es2016"
```

libを以下のように変更します。

```json:tsconfig.json
"lib": [
      "es2016",
      "esnext.asynciterable",
      "dom"
]
```

# モデルクラスにtype-graphqlの定義を追加
クラスに対して@ObjectType()を、フィールドに対して@Field()を追加します。
importするのは、reflect-metadataとtype-graphqlです。
以下のコードは、sequelize-typescriptも使っているので、その定義も含まれています。

```typescript:account.ts
import 'reflect-metadata';
import { ObjectType, Field, ID } from 'type-graphql';
import { Table, Column, Model, DataType, PrimaryKey, Unique, Default } from 'sequelize-typescript';

@ObjectType()
@Table
export class Account extends Model<Account> {
    @Field(type => ID)
    @PrimaryKey
    @Unique
    @Default(DataType.UUIDV4)
    @Column(DataType.UUID)
    id?: string;
    @Field()
    @Column(DataType.STRING)
    name: string;
    @Field()
    @Column(DataType.STRING)
    kana: string;
    @Field()
    @Column(DataType.STRING)
    email: string;
    @Field()
    @Column(DataType.STRING)
    postcode: string;
    @Field()
    @Column(DataType.STRING)
    address: string;
    @Field()
    @Column(DataType.STRING)
    phone: string;
    @Field()
    @Column(DataType.STRING)
    password: string;

    constructor(name: string, kana: string, email: string, postcode: string, address: string, phone: string, password: string) {
        super();

        this.name = name;
        this.kana = kana;
        this.email = email;
        this.postcode = postcode;
        this.address = address;
        this.phone = phone;
        this.password = password;
    }
}
```

# Resolverクラスを作成
graphqlのリゾルバクラスを作成します。

```typescript:accountresolver.ts
import 'reflect-metadata';
import { Resolver, Mutation, Arg, InputType, Field, Query } from 'type-graphql';
import { Account } from '../models/account';

@InputType()
export class AccountInput implements Partial<Account> {
    @Field()
    name: string;
    @Field()
    kana: string;
    @Field()
    email: string;
    @Field()
    postcode: string;
    @Field()
    address: string;
    @Field()
    phone: string;
    @Field()
    password: string;

    constructor(name: string, kana: string, email: string, postcode: string, address: string, phone: string, password: string) {
        this.name = name;
        this.kana = kana;
        this.email = email;
        this.postcode = postcode;
        this.address = address;
        this.phone = phone;
        this.password = password;
    }
}

@Resolver(of => Account)
export class AccountResolver {
    @Query(returns => Account)
    async account() {
        const acc: Account = new Account('name', 'kana', 'email', 'postcode', 'address', 'phone', 'password');

        return Promise.resolve(acc);
    }

    @Mutation(returns => Account)
    addAccount(
        @Arg('account') accountInput: AccountInput
    ): Promise<Account> {
        const acc: Account = new Account('name', 'kana', 'email', 'postcode', 'address', 'phone', 'password');

        return Promise.resolve(acc);
    }
}
```

# expressにGraphqlを組み込む
expressのapp.tsに、Graphqlを組み込んで行きます。

```typescript:app.ts
import graphqlHTTP from 'express-graphql';
import { buildSchema } from 'type-graphql';
import { AccountResolver } from './resolvers/accountresolver';

// Graphqlを組み込む
async function bootstrap() {
  const schema = await buildSchema({
    resolvers: [ AccountResolver ]
  });

  app.use('/graphql', graphqlHTTP({
    schema: schema,
    graphiql: true
  }));
}

bootstrap().catch(err => {
  console.log(err);
});
```
# ビルドしてGraphqlにアクセス
プロジェクトをビルド、実行し、http://localhost:3000/graphqlにアクセスすると、Graphqlのクエリエディタが表示されます(Graphiql)

![graphiql.png](https://qiita-image-store.s3.amazonaws.com/0/334727/401f8eb3-8605-4269-5df8-17844ed9159c.png)