Casual Developers Note

エンジニアやデザイナー向けの技術情報・英語学習情報・海外留学情報・海外旅行情報を提供中。世界を旅して人生を楽しもう。

  • ホーム
  • 技術 Tips & Tutorials
  • 技術塾
  • ライフハック
  • 海外留学
  • 英語学習
  • コラム
  • お問い合わせ
現在の場所:ホーム / アーカイブKD

2019年8月30日 By KD コメントを書く

Jenkins爆速入門: 5日間ブートキャンプ (NodeJS&Docker編)

Jenkins爆速入門: 5日間ブートキャンプ (NodeJS&Docker編)

Jenkinsに入門したいエンジニア向けにこのブログの記事の中から厳選した爆速で学べる記事を紹介します。

はじめに

JenkinsはDevOpsに欠かせない継続的インテグレーション(CI)や継続的デプロイ(CD)を実現するための専用ツールです。自前でサーバーを用意してCI/CD環境を構築する場合はこれ一択と言ってよいでしょう。この使い方を学べば、開発したアプリケーションのCI/CD環境を自分で構築できるようになります。

それでは、ブートキャンプを始めましょう。

カリキュラム

Jennkinsのインストールから基本的な使い方、メールやSlack通知、GitHubアカウント統合までを学ぶカリキュラムです。

【1日目】爆速でJenkinsをマスターしよう(NodeJS編) ~ JenkinsセットアップからNodeJS自動テスト、Job DSLまで ~

爆速でJenkinsをマスターしよう(NodeJS編) ~ JenkinsセットアップからNodeJS自動テスト、Job DSLまで ~

【2日目】爆速でJenkinsをマスターしよう(Docker編) ~ JenkinsコンテナへのDockerインストール方法からJob DSL、Jenkins Pipelineまで ~

爆速でJenkinsをマスターしよう(Docker編) ~ JenkinsコンテナへのDockerインストール方法からJob DSL、Jenkins Pipelineまで ~

【3日目】爆速でJenkinsをマスターしよう(メール通知編) ~ パイプラインのビルド失敗時にメールで通知する方法 ~

爆速でJenkinsをマスターしよう(メール通知編) ~ パイプラインのビルド失敗時にメールで通知する方法 ~

【4日目】爆速でJenkinsをマスターしよう(Slack通知編) ~ パイプラインのビルド失敗時にSlackで通知する方法 ~

爆速でJenkinsをマスターしよう(Slack通知編) ~ パイプラインのビルド失敗時にSlackで通知する方法 ~

【5日目】爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~

爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~

最後に

いかがでしたか?このカリキュラムを完遂したなら、Jenkinsをマスターできたに違いありません。これであなたも立派なDevOpsエンジニアの仲間入りですね!それでは。

カテゴリ : 技術塾 タグ : bootcamp, docker, jenkins, jenkins-github-organization, jenkins-job-dsl, jenkins-pipeline, nodejs

2019年7月22日 By KD コメントを書く

開発用データベースのためのDocker Composeの設定方法 (MySQL/PostgreSQL/MongoDB編)

開発用データベースのためのDocker Composeの設定方法 (MySQL/PostgreSQL/MongoDB編)

開発環境構築時にデータベースをDocker Composeを使って手軽に構築する方法を紹介します。

はじめに

開発環境構築はDockerで構築するのがもっと簡単です。そして、アプリケーションの開発のためにはローカル環境にデータベースを迅速に準備する必要があります。今回は、Docker Composeを使って、MySQL、PostgreSQL、MongoDBのデータベースを対象に、データベースを構築し、シードを準備する方法を紹介します。

前提条件

以下の準備が事前に完了している必要があります。

  • Dockerがインストールされていること

詳しくは「環境」を参照してください。

MySQLのDocker Composeによる設定とシードの追加

まずは、MySQLの設定方法です。

ベースの作成

必要なフォルダとファイルを作成します。

$ touch docker-compose.yml
$ mkdir -p mysql/initdb
$ touch mysql/initdb/1_create_tables.sql
$ touch mysql/initdb/2_insert_seed.sql

Docker Composeの設定ファイルとシード用SQLの作成

Docker Composeの設定ファイルとシードを入れいる簡単なSQLを作成します。

docker-compose.yml

version: '3'

services:
  mysql:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      TZ: "Asia/Tokyo"
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: test_db
      MYSQL_USER: test
      MYSQL_PASSWORD: test
    ports:
      - 3306:3306
    volumes:
      - mysql:/var/lib/mysql
      - ./mysql/initdb:/docker-entrypoint-initdb.d

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    restart: always
    ports:
      - 8080:80
    environment:
      PMA_ARBITRARY: 1
      PMA_HOST: mysql
      PMA_USER: root
      PMA_PASSWORD: root
    depends_on:
      - mysql

volumes:
 mysql:

1_create_tables.sql

create table users
(
  id serial primary key,
  username varchar(50) unique not null,
  password varchar(50) not null,
  email varchar(255) unique not null
);

2_insert_seed.sql

insert into users (username, password, email) values ('keid', 'keidpass', 'keid@developer.com');
insert into users (username, password, email) values ('jobs', 'jobspass', 'jobs@developer.com');
insert into users (username, password, email) values ('mask', 'maskpass', 'mask@developer.com');

動作確認

それでは、Docker上でMySQLを起動してみましょう。

$ docker-compose up -d
$ docker-compose ps
          Name                        Command               State                 Ports              
-----------------------------------------------------------------------------------------------------
local-mysql_mysql_1        docker-entrypoint.sh --def ...   Up      0.0.0.0:3306->3306/tcp, 33060/tcp
local-mysql_phpmyadmin_1   /docker-entrypoint.sh apac ...   Up      0.0.0.0:8080->80/tcp  
$ mysql -h 0.0.0.0 -P 3306 -u test -p
Enter password: 
...
mysql> use test_db
...
mysql> select * from users;
+----+----------+----------+--------------------+
| id | username | password | email              |
+----+----------+----------+--------------------+
|  1 | keid     | keidpass | keid@developer.com |
|  2 | jobs     | jobspass | jobs@developer.com |
|  3 | mask     | maskpass | mask@developer.com |
+----+----------+----------+--------------------+
3 rows in set (0.01 sec)
mysql> exit
Bye

OKですね。

次に「http://localhost:8080/」にアクセスしてPhpMyAdminが動いていることも確認してみましょう。

NewImage

ばっちりですね。

PostgreSQLのDocker Composeによる設定とシードの追加

次に、PostgreSQLの設定方法です。

ベースの作成

必要なフォルダとファイルを作成します。

$ touch docker-compose.yml
$ mkdir -p postgres/initdb
$ touch postgres/initdb/1_create_tables.sql
$ touch postgres/initdb/2_insert_seed.sql

Docker Composeの設定ファイルとシード用SQLの作成

Docker Composeの設定ファイルとシードを入れいる簡単なSQLを作成します。

docker-compose.yml

version: '3'

services:
  postgres:
    image: postgres:11.4-alpine
    restart: always
    environment:
      TZ: "Asia/Tokyo"
      POSTGRES_USER: test
      POSTGRES_PASSWORD: test
      POSTGRES_DB: test_db
    ports:
      - 5432:5432
    volumes:
      - postgres:/var/lib/postgresql/data
      - ./postgres/initdb:/docker-entrypoint-initdb.d

  pgadmin:
    image: dpage/pgadmin4
    restart: always
    ports:
      - 8080:80
    environment:
      PGADMIN_DEFAULT_EMAIL: admin@example.com
      PGADMIN_DEFAULT_PASSWORD: admin
    volumes:
      - pgadmin:/var/lib/pgadmin
    depends_on:
      - postgres

volumes:
  postgres:
  pgadmin:

1_create_tables.sql

create table users
(
  id serial primary key,
  username varchar(50) unique not null,
  password varchar(50) not null,
  email varchar(255) unique not null
);

2_insert_seed.sql

insert into users (username, password, email) values ('keid', 'keidpass', 'keid@developer.com');
insert into users (username, password, email) values ('jobs', 'jobspass', 'jobs@developer.com');
insert into users (username, password, email) values ('mask', 'maskpass', 'mask@developer.com');

動作確認

それでは、Docker上でPostgreSQLを起動してみましょう。

$ docker-compose up -d
$ docker-compose ps
          Name                         Command              State               Ports            
-------------------------------------------------------------------------------------------------
local-postgres_pgadmin_1    /entrypoint.sh                  Up      443/tcp, 0.0.0.0:8080->80/tcp
local-postgres_postgres_1   docker-entrypoint.sh postgres   Up      0.0.0.0:5432->5432/tcp 
$ psql -h 0.0.0.0 -p 5432 -d test_db -U test
Password for user test: 
...
test_db=# select * from users;
 id | username | password |       email        
----+----------+----------+--------------------
  1 | keid     | keidpass | keid@developer.com
  2 | jobs     | jobspass | jobs@developer.com
  3 | mask     | maskpass | mask@developer.com
(3 rows)
test_db=# \q

大丈夫ですね。

次に「http://localhost:8080/」にアクセスしてpgAdminが動いていることも確認してみましょう。

NewImage

起動は問題なかったので、「新しいサーバを追加」からデータベースに接続します。

NewImage

ホスト名、ポート番号、ユーザ名、パスワードを入力して、「保存」をクリックします。

NewImage

データベースを選択して、ユーザを表示してみます。

NewImage

シードもちゃんと入っていますね。

なお、今回はpgAdminのデータもボリュームに保存しているので、一旦接続情報を入力しておけば、Dockerを停止しても接続情報は保持されます。

MongoDBのDocker Composeによる設定とシードの追加

最後に、MongoDBの設定方法です。

ベースの作成

必要なフォルダとファイルを作成します。

$ touch docker-compose.yml
$ mkdir -p mongo/seed
$ touch mongo/seed/users.json

Docker Composeの設定ファイルとシード用JSONファイルの作成

Docker Composeの設定ファイルとシードとなるJSONファイルを作成します。

docker-compose.yml

version: '3'

services:
  mongo:
    image: mongo:4.0
    restart: always
    ports:
      - 27017:27017
    volumes:
      - mongo:/data/db

  mongo-seed:
    image: mongo:4.0
    command: mongoimport --host mongo:27017 --db test_db --collection users --type json --file /seed/users.json --jsonArray
    volumes:
      - ./mongo/seed:/seed
    depends_on:
      - mongo

  mongo-express:
    image: mongo-express
    restart: always
    ports:
      - 8081:8081
    environment:
      ME_CONFIG_MONGODB_SERVER: mongo
      ME_CONFIG_MONGODB_PORT: 27017
    depends_on:
      - mongo

volumes:
  mongo:

users.json

[
  {
    "username": "keid",
    "password": "keidpass",
    "email": "keid@developer.com"
  },
  {
    "username": "jobs",
    "password": "jobspass",
    "email": "jobs@developer.com"
  },
  {
    "username": "mask",
    "password": "maskpass",
    "email": "mask@developer.com"
  }
]

動作確認

それでは、Docker上でMongoDBを起動してみましょう。

$ docker-compose up -d
$ docker-compose ps
            Name                           Command               State             Ports          
--------------------------------------------------------------------------------------------------
local-mongodb_mongo-express_1   tini -- /docker-entrypoint ...   Up       0.0.0.0:8081->8081/tcp  
local-mongodb_mongo-seed_1      docker-entrypoint.sh mongo ...   Exit 0                           
local-mongodb_mongo_1           docker-entrypoint.sh mongod      Up       0.0.0.0:27017->27017/tcp
$ mongo --port 27017
...
> use test_db
switched to db test_db
> db
test_db
> show collections
users
> db.users.find()
{ "_id" : ObjectId("5d317fda80a257d9f5c44379"), "username" : "keid", "password" : "keidpass", "email" : "keid@developer.com" }
{ "_id" : ObjectId("5d317fda80a257d9f5c4437a"), "username" : "mask", "password" : "maskpass", "email" : "mask@developer.com" }
{ "_id" : ObjectId("5d317fda80a257d9f5c4437b"), "username" : "jobs", "password" : "jobspass", "email" : "jobs@developer.com" }
> exit
bye

次に「http://localhost:8081/」にアクセスしてMongo Expressが動いていることも確認してみましょう。

NewImage

OKです。データも入っていますね。

おまけ(PrismaのDocker Composeの自動生成とシードの追加)

ベースの作成

Prismaの場合はコマンドラインからDocker Composeの設定を自動生成できます。

$ npm i -g prisma
$ prisma init prisma
? Set up a new Prisma server or deploy to an existing server? Create new database
? What kind of database do you want to deploy to? MySQL
? Select the programming language for the generated Prisma client Prisma JavaScript Client
...
$ cd prisma/
$ touch seed.graphql
$ tree
.
├── datamodel.prisma
├── docker-compose.yml
├── generated
│   └── prisma-client
│       ├── index.d.ts
│       ├── index.js
│       └── prisma-schema.js
├── prisma.yml
└── seed.graphql

Docker Composeの設定ファイルGraphQLファイルの作成

Docker Composeの設定ファイルとスキーマとシードのGraphQLファイルを作成します。

docker-compose.yml

version: '3'
services:
  prisma:
    image: prismagraphql/prisma:1.34
    restart: always
    ports:
    - "4466:4466"
    environment:
      PRISMA_CONFIG: |
        port: 4466
        databases:
          default:
            connector: mysql
            host: mysql
            user: root
            password: prisma
            rawAccess: false
            port: 3306
            migrations: false
  mysql:
    image: mysql:5.7
    restart: always
    ports:
    - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: prisma
    volumes:
      - mysql:/var/lib/mysql
volumes:
  mysql:

「rawAccess」と「migrations」をfalseにするのと、MySQLのポートの開放をします。

prisma.yml

endpoint: http://localhost:4466
datamodel: datamodel.prisma

generate:
  - generator: javascript-client
    output: ./generated/prisma-client/

seed:
  import: seed.graphql

hooks:
  post-deploy:
    - prisma generate

datamodel.prisma

type User {
  id: ID! @id
  username: String!
  password: String!
  email: String!
}

seed.graphql

mutation {
  user1: createUser(
    data: {
      username: "keid"
      password: "keidpass"
      email: "keid@developer.com"
    }
  ) {
    id
  }

  user2: createUser(
    data: {
      username: "jobs"
      password: "jobspass"
      email: "jobs@developer.com"
    }
  ) {
    id
  }

  use3: createUser(
    data: {
      username: "mask"
      password: "maskpass"
      email: "mask@developer.com"
    }
  ) {
    id
  }
}

動作確認

それでは、Docker上でPrismaを起動してみましょう。

$ docker-compose up -d
$ docker-compose ps
     Name                   Command             State                 Ports              
-----------------------------------------------------------------------------------------
prisma_mysql_1    docker-entrypoint.sh mysqld   Up      0.0.0.0:3306->3306/tcp, 33060/tcp
prisma_prisma_1   /bin/sh -c /app/start.sh      Up      0.0.0.0:4466->4466/tcp 
$ prisma deploy
$ mysql -h 0.0.0.0 -P 3306 -u root -p
Enter password: 
...
mysql> use default@defaut;
...
mysql> show tables;
+---------------------------+
| Tables_in_default@default |
+---------------------------+
| User                      |
+---------------------------+
1 row in set (0.00 sec)
mysql> select * from User;
+---------------------------+----------+----------+--------------------+
| id                        | username | password | email              |
+---------------------------+----------+----------+--------------------+
| cjy9vplln000k07357qmb4lkn | keid     | keidpass | keid@developer.com |
| cjy9vplny000o0735ua7ab9w5 | jobs     | jobspass | jobs@developer.com |
| cjy9vploa000s0735xt18lpmu | mask     | maskpass | mask@developer.com |
+---------------------------+----------+----------+--------------------+
3 rows in set (0.00 sec)
mysql> exit
Bye

次に「http://localhost:4466/」にアクセスしてGraphQLで確認してみましょう。

NewImage

OKですね。

さらに「prisma admin」を実行するか、または「http://localhost:4466/_admin」にアクセスしてAdminページで確認してみましょう。

NewImage

こちらも問題ないですね。

最後に

いかがでしたか?これで、Docker Composeでローカルに開発用のデータベースを簡単に構築できるようになったことでしょう。それでは。

環境

  • Docker: 18.09.2
  • Docker Compose: 1.23.2
  • NPM: 6.10.0
  • Prisma: 1.34.1

カテゴリ : 技術 Tips & Tutorials タグ : database, docker, docker-compose, mongodb, mysql, postgresql, prisma

2019年7月18日 By KD コメントを書く

令和時代にGraphQLを知らないエンジニアはいらない!GraphQLとPrismaのバックエンド開発入門(GraphQL Yoga編)

令和時代にGraphQLを知らないエンジニアはいらない!GraphQLとPrismaのバックエンド開発入門(GraphQL Yoga編)

GraphQLとPrismaを用いたバックエンドのAPI開発をGraphQL Yogaを使って実現する方法を紹介します。

はじめに

平成後半はAPIの全盛期でした。SaaSが一般化し、SOAPなどのXMLベースの複雑なAPIからJSONベースのシンプルなAPIが主流となり、バックエンドのAPIと言えばJSONベースのREST APIを指すことがほとんどになりました。しかし、REST APIはフォーマットがJSONでシンプルになった一方で、インターフェースに明確な仕様がなく、開発者によって微妙に使い方が異なるという独自仕様の乱立に繋がりました。これはなんとかしなければいけません。エンジニアはいつももっと分かりやすくシンプルにならないかを考えています。そんな平成最後にFacebookが示した一つの解がGraphQLです。GraphQLはエンドポイントを一つにし、インターフェースを統一することで、新しいAPIを誕生させました。まだ発展途上の技術ではありますが、令和の新しい時代に相応しいクールな技術であることは間違いありません。

今回は、GraphQLとPrismaを用いて、バックエンドのAPIを作ってみましょう。

GraphQLとは?

GraphQLとは、APIのために作られたクエリー言語であり、型システムを使ってスキーマを定義することで、統一的なインターフェースを提供する仕組みです。エンドポイントが一つになるため、REST APIの時のように複数のエンドポイントを必要とせず、シンプルに設計されています。さらに、スキーマの情報からドキュメントも自動的に作られるため、APIドキュメントを作る作業からも開放されます。良いところばかりですね。

Prismaとは?

Prismaとは、データベースのための新しいORマッパーです。Prismaサーバーとして、バックエンドAPIとデータベースの間に配置することで、MySQL、PostgreSQL、MongoDBといった具体的なデータベースを完全に隠蔽し、バックエンドAPIからはPrismaが自動生成したGraphQLのクエリーでアクセスできるようになります。データベースアクセスをGraphQLのインターフェースにしてしまうということです。

GraphQLとPrismaのバックエンドを開発しよう

それでは、GraphQLとPrismaのバックエンドアプリケーションをつくってみましょう。

前提条件

以下の準備が完了している必要があります。

  • NodeJSがインストールされていること
  • Dockerがインストールされていること

詳しい環境は「環境」を参照してください。

ベースを作る

まずは、必要はファイルとフォルダを作り、パッケージをインストールします。

$ mkdir yoga-graphql-prisma-backend
$ cd yoga-graphql-prisma-backend
$ yarn init -y
$ yarn add -D @babel/cli @babel/core @babel/preset-env @babel/node
$ touch .babelrc
$ vi .babelrc
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "esmodules": true
        }
      }
    ]
  ]
}
$ yarn add -D nodemon
$ yarn add -D prisma
$ yarn add graphql-yoga prisma-client-lib
$ mkdir src
$ touch src/index.js
$ touch src/schema.graphql
$ touch src/resolvers.js
$ vi package.json
{
...
  "scripts": {
    "dev": "nodemon --ext js,graphql --exec babel-node src/index.js",
    "prisma": "prisma"
  },
...
}
$ yarn prisma init prisma
...
? Set up a new Prisma server or deploy to an existing server? Create new database
? What kind of database do you want to deploy to? MySQL
? Select the programming language for the generated Prisma client Prisma JavaScript Client
...
$ tree prisma/ -L 1
prisma/
├── datamodel.prisma
├── docker-compose.yml
├── generated
└── prisma.yml
$ mv prisma/generated src/
$ tree -I 'node_modules' -L 3
.
├── package.json
├── prisma
│   ├── datamodel.prisma
│   ├── docker-compose.yml
│   └── prisma.yml
├── src
│   ├── generated
│   │   └── prisma-client
│   ├── index.js
│   ├── resolvers.js
│   └── schema.graphql
└── yarn.lock

今回はゼロからスクラッチで作りますが、GraphQL CLIを使えば一瞬で類似した構成を構築できます。

Prismaでデータベース部分を開発する

次に、Prismaでデータベースのスキーマを作りましょう。今回は、よくあるフリーマケットアプリを意識して、User、Product、Reviewのスキーマを作ってみることにしましょう。なお、Prismaの後ろで動くデータベースはMySQLとし、Docker上で可動させることにします。

docker-compose.yml

version: '3'

services:
  prisma:
    image: prismagraphql/prisma:1.34
    restart: always
    ports:
      - 4466:4466
    environment:
      PRISMA_CONFIG: |
        port: 4466
        databases:
          default:
            connector: mysql
            host: mysql
            user: root
            password: prisma
            rawAccess: false
            port: 3306
            migrations: false

  mysql:
    image: mysql:5.7
    restart: always
    ports:
    - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: prisma
    volumes:
      - mysql:/var/lib/mysql

volumes:
  mysql

なお、現時点では「rawAccess」と「migrations」はfalseにしないとPrismaのAdminページが動かないので注意が必要です。

prisma.yml

endpoint: http://localhost:4466

datamodel: datamodel.prisma

generate:
  - generator: javascript-client
    output: ../src/generated/prisma-client

hooks:
  post-deploy:
    - prisma generate

datamodel.prisma

type User {
  id: ID! @id
  name: String!
  email: String! @unique
  products: [Product!]! @relation(name: "ProductToUser", onDelete: CASCADE)
  reviews: [Review!]! @relation(name: "ReviewToUser", onDelete: CASCADE)
}

type Product {
  id: ID! @id
  name: String!
  price: Int!
  onSale: Boolean! @default(value: false)
  author: User! @relation(name: "ProductToUser", onDelete: SET_NULL)
  reviews: [Review!]! @relation(name: "ReviewToProduct", onDelete: CASCADE)
}

type Review {
  id: ID! @id
  text: String!
  author: User! @relation(name: "ReviewToUser", onDelete: SET_NULL)
  product: Product! @relation(name: "ReviewToProduct", onDelete: SET_NULL)
}

PrismaとMySQLを起動しましょう。

$ docker-compose -f prisma/docker-compose.yml up -d
$ docker-compose -f prisma/docker-compose.yml ps
     Name                   Command             State                 Ports              
-----------------------------------------------------------------------------------------
prisma_mysql_1    docker-entrypoint.sh mysqld   Up      0.0.0.0:3306->3306/tcp, 33060/tcp
prisma_prisma_1   /bin/sh -c /app/start.sh      Up      0.0.0.0:4466->4466/tcp
$ yarn prisma deploy

「prisma generate」コマンドでPrismaクライアントが自動的に更新され、「prisma deploy」により、スキーマがデータベースに反映されます。今回は「prisma.yml」の「hooks」で「prisma deploy」だけでこれらが実行さえるようにしてあります。

「http://localhost:4466/」を開くとPrismaのGraphQL用のページが表示されるので、そこからGraphQLを用いてデータベースへアクセスすることができます。

「http://localhost:4466/_admin」を開くとPrismaのAdminページが表示され、GUIでデータベースを操作することが可能です。「prisma admin」で自動的にページを開くこともできます。

Prismaの詳しい使い方は公式ドキュメントを参照して下さい。

GraphQLでCRUDのAPIを開発する

GraphQL Yogaを使ってGraphQLサーバーを構築しましょう。

index.js

import { GraphQLServer } from 'graphql-yoga';
import { prisma } from './generated/prisma-client';
import * as resolvers from './resolvers';

const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',
  resolvers,
  context: {
    prisma,
  },
});

server.start(() => console.log('GraphQL server is up on 4000...'));

schema.graphql

type Query {
  users: [User!]!
  user(id: String!): User!
  products: [Product!]!
  productsOnSale: [Product!]!
  product(id: String!): Product!
  reviews: [Review!]!
  review(id: String!): Review!
}

type Mutation {
  createUser(name: String!, email: String!): User!
  deleteUser(id: String!): String!
  createProduct(
    name: String!
    price: Int!
    onSale: Boolean
    userId: String!
  ): Product!
  updateProduct(id: ID!, name: String, price: Int, onSale: Boolean): Product!
  deleteProduct(id: String!): String!
  createReview(text: String!, userId: String!, productId: String!): Review!
  deleteReview(id: String!): String!
}

type User {
  id: ID!
  name: String!
  email: String!
  products: [Product!]!
  reviews: [Review!]!
}

type Product {
  id: ID!
  name: String!
  price: Int!
  onSale: Boolean!
  author: User!
  reviews: [Review!]!
}

type Review {
  id: ID!
  text: String!
  author: User!
  product: Product!
}

resolvers.js

const Query = {
users: (parent, args, { prisma }, info) => prisma.users(),
user: (parent, { id }, { prisma }, info) => prisma.user({ id }),
products: (parent, args, { prisma }, info) => prisma.products(),
productsOnSale: (parent, args, { prisma }, info) =>
prisma.products({ where: { onSale: true } }),
product: (parent, { id }, { prisma }, info) => prisma.product({ id }),
reviews: (parent, args, { prisma }, info) => prisma.reviews(),
review: (parent, { id }, { prisma }, info) => prisma.review({ id }),
};
const Mutation = {
createUser(parent, { name, email }, { prisma }, info) {
return prisma.createUser({ name, email });
},
async deleteUser(parent, { id }, { prisma }, info) {
const user = await prisma.user({ id });
if (!user) {
throw new Error('User not found!');
}
const deletedUser = await prisma.deleteUser({ id });
return deletedUser.id;
},
async createProduct(
parent,
{ name, price, onSale, userId },
{ prisma },
info
) {
const user = await prisma.user({ id: userId });
if (!user) {
throw new Error('User not found!');
}
const product = await prisma.createProduct({
name,
price,
onSale,
author: {
connect: {
id: userId,
},
},
});
return { ...product, author: user };
},
async updateProduct(parent, { id, name, price, onSale }, { prisma }, info) {
const product = await prisma.product({ id });
if (!product) {
throw new Error('Product not found!');
}
const updatedProduct = await prisma.updateProduct({
data: { name, price, onSale },
where: { id },
});
return updatedProduct;
},
async deleteProduct(parent, { id }, { prisma }, info) {
const product = await prisma.product({ id });
if (!product) {
throw new Error('Product not found!');
}
const deletedProduct = await prisma.deleteProduct({ id });
return deletedProduct.id;
},
async createReview(parent, { text, userId, productId }, { prisma }, info) {
const user = await prisma.user({ id: userId });
if (!user) {
throw new Error('User not found!');
}
const product = await prisma.product({ id: productId });
if (!product) {
throw new Error('Product not found!');
}
const review = await prisma.createReview({
text,
author: {
connect: {
id: userId,
},
},
product: {
connect: {
id: productId,
},
},
});
return { ...review, author: user, product };
},
async deleteReview(parent, { id }, { prisma }, info) {
const review = await prisma.review({ id });
if (!review) {
throw new Error('Review not found!');
}
const deletedReview = await prisma.deleteReview({ id });
return deletedReview.id;
},
};
const User = {
products: (parent, args, { prisma }, info) =>
prisma.user({ id: parent.id }).products(),
reviews: (parent, args, { prisma }, info) =>
prisma.user({ id: parent.id }).reviews(),
};
const Product = {
author: (parent, args, { prisma }, info) =>
prisma.product({ id: parent.id }).author(),
reviews: (parent, args, { prisma }, info) =>
prisma.product({ id: parent.id }).reviews(),
};
const Review = {
author: (parent, args, { prisma }, info) =>
prisma.review({ id: parent.id }).author(),
product: (parent, args, { prisma }, info) =>
prisma.review({ id: parent.id }).product(),
};
export { Query, Mutation, User, Product, Review };

これで実装は完了です。

動作確認

完成したバックエンドAPIの動作確認をしてみましょう。

まずは、サーバーを起動します。

$ yarn dev
...
GraphQL server is up on 4000...

「http://localhost:4000/」を開き、以下のGraphQLのクエリーで確認してみましょう。

Userへのクエリー

query Users {
users {
id
name
email
products {
id
name
price
onSale
}
reviews {
id
text
}
}
}
query User {
user(id: "cjy74aney00nz070468vkvyb9") {
id
name
email
products {
id
name
price
onSale
}
reviews {
id
text
}
}
}
mutation CreateUser {
createUser (name: "Keid", email: "keid@developer.com") {
id
name
email
products {
name
}
reviews {
text
}
}
}
mutation DeleteUser {
deleteUser(id: "cjy74330m00na0704prykyccw")
}

Productへのクエリー

query Products {
products {
id
name
price
onSale
author {
id
name
email
}
reviews {
id
text
}
}
}
query ProductsOnSale {
productsOnSale {
id
name
price
onSale
}
}
query Product {
product(id: "cjy74bwk900on07044uc259vh") {
id
name
price
onSale
author {
id
name
email
}
reviews {
id
text
}
}
}
mutation CreateProduct {
createProduct(name: "iPhone8", price: 60000, userId: "cjy74aney00nz070468vkvyb9") {
id
name
price
onSale
author {
id
name
email
}
}
}
mutation UpdateProduct {
updateProduct(id: "cjy74bwk900on07044uc259vh", onSale: true) {
id
name
price
onSale
author {
id
name
email
}
}
}
mutation DeleteProduct {
deleteProduct(id: "cjy74bv4h00of07045g8eipuj")
}

Reviewへのクエリー

query Reviews {
reviews {
id
text
author {
id
name
email
}
product {
id
name
price
onSale
}
}
}
query Review {
review(id: "cjy74v0zf00qa0704oppn1hr0") {
id
text
author {
id
name
email
}
product {
id
name
price
onSale
}
}
}
mutation CreateReview {
createReview(
text: "The product is great!",
userId: "cjy74aney00nz070468vkvyb9", 
productId: "cjy74bwk900on07044uc259vh")
{
id
text
author {
id
name
email
}
product {
id
name
price
onSale
}
}
}
mutation DeleteReview {
deleteReview(id: "cjy74uvu700py0704a2c0hyub")
}

なお、もちろんIDは適切に設定する必要があります。

NewImage

このように期待通りに動作しました。いろいろ試してみましょう!

おまけ

Subscriptionの実装

GraphQLの他の機能としてSubscriptionがあります。Subscriptionを簡単に説明すると、WebSocketを使ってイベント発生時にクライントに通知するGraphQLの仕組みです。

今回はおまけとして、Reviewが追加された時に通知する実装を追加しましょう。

index.js

import { GraphQLServer, PubSub } from 'graphql-yoga';
import { prisma } from './generated/prisma-client';
import * as resolvers from './resolvers';
const pubsub = new PubSub();
const server = new GraphQLServer({
typeDefs: './src/schema.graphql',
resolvers,
context: {
prisma,
pubsub,
},
});
server.start(() => console.log('GraphQL server is up on 4000...'));

schema.graphql(抜粋)

...
type Subscription {
reviewCreated: Review!
}
...

resolvers.js(抜粋)

const Mutation = {
...
async createReview(
parent,
{ text, userId, productId },
{ prisma, pubsub },
info
) {
const user = await prisma.user({ id: userId });
if (!user) {
throw new Error('User not found!');
}
const product = await prisma.product({ id: productId });
if (!product) {
throw new Error('Product not found!');
}
const review = await prisma.createReview({
text,
author: {
connect: {
id: userId,
},
},
product: {
connect: {
id: productId,
},
},
});
const newReview = { ...review, author: user, product };
pubsub.publish('REVIEW_CREATED', {
reviewCreated: newReview,
});
return newReview;
},
...
};
...
const Subscription = {
reviewCreated: {
subscribe: (parent, args, { pubsub }, info) =>
pubsub.asyncIterator('REVIEW_CREATED'),
},
};

実装完了です。それでは、動作確認しましょう。

「http://localhost:4000/」を開き、以下を実行しましょう。

subscription SubscribeReview {
reviewCreated {
id
text
author {
id
name
email
}
product {
id
name
price
onSale
}
}
}

NewImage

NewImage

NewImage

Reviewの作成時に、作成されたReviewを取得できました。

最後に

いかがでしたか?これで令和時代に相応しいGraphQLを使いこなすエンジニアになることができましたね!GraphQLはまだまだ新しい技術ですが、今までのREST APIに取って代わっていくと思いますので、機会があれば積極的に使っていきましょう。それでは。

環境

  • NodeJS: v12.3.1
  • Yarn: 1.16.0
  • Docker: 18.09.2
  • @babel/cli: 7.5.0
  • @babel/core: 7.5.4
  • @babel/node: 7.5.0
  • @babel/preset-env: 7.5.4
  • nodemon: 1.19.1
  • prisma: 1.34.1
  • graphql-yoga: 1.18.1
  • prisma-client-lib: 1.34.1

カテゴリ : 技術 Tips & Tutorials タグ : backend, graphql, graphql-yoga, prisma

  • « 前のページ
  • 1
  • 2
  • 3
  • 4
  • 5
  • …
  • 51
  • 次のページ »

ブログ更新情報や海外の関連情報などを配信する無料メルマガ

Sponsored Links

About Author

KD

世界を旅し日本を愛するエンジニア。大学でコンピュータサイエンスの楽しさを学び、日本の大手IT企業で働く中で、新しい技術やスケールするビジネスが北米にある事に気づく。世界に挑戦するための最大の壁が英語であったため、フィリピン留学およびカナダ留学を経て英語を上達させた。現在は日本在住でエンジニアとして働きつつ、次の挑戦に備えて世界の動向を注視している。挑戦に終わりはない。このブログでは、エンジニアやデザイナー向けの技術情報から、海外に留学したい人向けの留学情報、海外に興味がある人向けの海外旅行情報など、有益な情報を提供しています。

https://casualdevelopers.com/

最近の投稿

  • 2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介

    2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介

    2020年1月13日
  • 今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~

    今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~

    2019年11月4日
  • ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

    ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

    2019年10月30日
  • BashからZshに移行する方法(Mac編)

    BashからZshに移行する方法(Mac編)

    2019年10月21日
  • Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

    Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

    2019年9月30日

カテゴリ

  • 技術 Tips & Tutorials (100)
  • 技術塾 (6)
  • ライフハック (26)
  • 海外留学 (12)
  • 英語学習 (3)
  • コラム (6)

アーカイブ

最高の学習のために

人気記事ランキング

  • SAKURAのメールボックスで独自ドメインのメールを設定し、Gmail経由で送受信する方法
    SAKURAのメールボックスで独自ドメインのメールを設定し、Gmail経由で送受信する方法
  • バンクーバー留学豆知識:バンクーバーのATMで日本の銀行のキャッシュカードを使ってお得にお金を引き出す方法
    バンクーバー留学豆知識:バンクーバーのATMで日本の銀行のキャッシュカードを使ってお得にお金を引き出す方法
  • MySQLで「ERROR 2003 (HY000): Can't connect to MySQL server」と怒られた時の対処法
    MySQLで「ERROR 2003 (HY000): Can't connect to MySQL server」と怒られた時の対処法
  • AWS Elastic BeanstalkでReactのDockerアプリケーションを稼働させる方法
    AWS Elastic BeanstalkでReactのDockerアプリケーションを稼働させる方法
  • Expressで「Cannot set headers after they are sent to the client」と怒られた時の対処法
    Expressで「Cannot set headers after they are sent to the client」と怒られた時の対処法
  • Google Adsense(アドセンス広告)で収益を受け取るまでの手順
    Google Adsense(アドセンス広告)で収益を受け取るまでの手順
  • Jupyter Notebookで「The kernel appears to have died. It will restart automatically.」というエラーが出た場合の原因と対処法
    Jupyter Notebookで「The kernel appears to have died. It will restart automatically.」というエラーが出た場合の原因と対処法
  • Heroku上にNginxでリバースプロキシを構築する方法
    Heroku上にNginxでリバースプロキシを構築する方法
  • AWS ECRとECSの入門(EC2編) ~ ECSのEC2版を使ってReactのDockerアプリケーションをAWS上で稼働させる方法 ~
    AWS ECRとECSの入門(EC2編) ~ ECSのEC2版を使ってReactのDockerアプリケーションをAWS上で稼働させる方法 ~
  • Amazon EC2インスタンスにSSHできなくなった時の対処法
    Amazon EC2インスタンスにSSHできなくなった時の対処法

Bitcoin寄付 / BTC Donation

Bitcoinを寄付しよう

BTC
Select Payment Method
Personal Info

Donation Total: BTC 0.0010

このブログの運営のためにBitcoinでの寄付を募集しています。お気持ち程度の寄付を頂けると管理者の励みになります。

Bitcoin寄付について知りたい方はこちらの記事へ

ビットコイン取引ならここ

  • ホーム
  • 技術 Tips & Tutorials
  • 技術塾
  • ライフハック
  • 海外留学
  • 英語学習
  • コラム
  • サイトマップ
  • タグ一覧
  • プライバシーポリシー
  • お問い合わせ

Copyright © 2023 KD - Casual Developers Notes