20190327のNode.jsに関する記事は6件です。

タブレットアプリとWeb上の両立プロジェクト開発(一)Node.jsをインストールします

タブレットアプリというのは、例えば、iPhoneやiPadなどの端末上で稼働しているアプリを指します。Webプロジェクトというのは、Webブラウザーで見ているウェブサイトを指します。
タブレットアプリの特徴は、随時にバックエンドのサーバに繋がりをしなくて、ネットワークがない場合はタブレットが独立に動いておいて、ネットワーク例えばWi-Fiが繋がった場合にはサーバに接続してタブレットのデータをサーバに同期しようとすることがあります。
ウェブサイトのほうも、頻繁にサーバへ接続することを下げる期待を持っていることがあります。
こういうことを実現するために、JavaScriptをメインにしているプロジェクトを作りたいです。
本章では、JavaScriptプロジェクトを作成する前の準備の一つとして、Node.jsをインストルします。

npmインストル

npmとは、Node.js用に作られたライブラリやパッケージを管理する為のパッケージ管理ツールです。
nnpmをインストルする前に、Nodebrewをインストルすることが必要です。
Nodebrewは、Node.jsのバージョン管理ツールにあたります。

#npmをインストル
brew install nodebrew
#Node.jsとnpmのインストール
nodebrew install-binary latest

もし、以下のエラーが出たら、下記のコマンドを実行して、ディレクトリを作成して、npmインストルを再度行います。
curl: (23) Failed writing body (0 != 941)
download failed: https://nodejs.org/dist/v7.10.0/node-v7.10.0-darwin-x64.tar.gz

mkdir -p ~/.nodebrew/src
nodebrew install-binary latest
#以下が表示
Fetching: https://nodejs.org/dist/v11.12.0/node-v11.12.0-darwin-x64.tar.gz
######################################################################## 100.0%
Installed successfully

上記のコマンドで最新版がインストールされます。
Node.jsを有効にします。

#バージョンの一覧を確認
nodebrew list
#バージョンの一覧が表示
v11.12.0
current: none
#current: noneとなっているため、必要なバージョンを有効化する。
nodebrew use v11.12.0
#バージョンの一覧を再確認
nodebrew list
#以下が表示
v11.12.0
current: v11.12.0

nodebrewが使いやすいように環境パスを通します。

echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
source ~/.bash_profile
#node.jsがインストル済かどうかを確認
node -v
#以下が表示
v11.12.0
#npmがインストル済かどうかを確認
npm -v
#以下が表示
6.7.0

上記ような各バージョーンが表示されたらNode.jsのインストールが終わりします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

タブレットとWeb両立プロジェクト開発(一)Node.jsをインストールします

タブレットプロジェクトというのは、例えば、iPhoneやiPadなどの端末上で稼働しているアプリを指します。Webプロジェクトというのは、Webブラウザーで見ているウェブサイトを指します。
タブレットアプリの特徴は、随時にバックエンドのサーバに繋がりをしなくて、ネットワークがない場合はタブレットが独立に動いておいて、ネットワーク例えばWi-Fiが繋がった場合にはサーバに接続してタブレットのデータをサーバに同期しようとすることがあります。
ウェブサイトのほうも、頻繁にサーバへ接続することを下げる期待を持っていることがあります。
こういうことを実現するために、JavaScriptをメインにしているプロジェクトを作りたいです。
本章では、JavaScriptプロジェクトを作成する前の準備の一つとして、Node.jsをインストルします。

npmインストル

npmとは、Node.js用に作られたライブラリやパッケージを管理する為のパッケージ管理ツールです。
nnpmをインストルする前に、Nodebrewをインストルすることが必要です。
Nodebrewは、Node.jsのバージョン管理ツールにあたります。

#npmをインストル
brew install nodebrew
#Node.jsとnpmのインストール
nodebrew install-binary latest

もし、以下のエラーが出たら、下記のコマンドを実行して、ディレクトリを作成して、npmインストルを再度行います。
curl: (23) Failed writing body (0 != 941)
download failed: https://nodejs.org/dist/v7.10.0/node-v7.10.0-darwin-x64.tar.gz

mkdir -p ~/.nodebrew/src
nodebrew install-binary latest
#以下が表示
Fetching: https://nodejs.org/dist/v11.12.0/node-v11.12.0-darwin-x64.tar.gz
######################################################################## 100.0%
Installed successfully

上記のコマンドで最新版がインストールされます。
Node.jsを有効にします。

#バージョンの一覧を確認
nodebrew list
#バージョンの一覧が表示
v11.12.0
current: none
#current: noneとなっているため、必要なバージョンを有効化する。
nodebrew use v11.12.0
#バージョンの一覧を再確認
nodebrew list
#以下が表示
v11.12.0
current: v11.12.0

nodebrewが使いやすいように環境パスを通します。
インストルした結果を確認します。

echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
source ~/.bash_profile
#node.jsがインストル済かどうかを確認
node -v
#以下が表示
v11.12.0
#npmがインストル済かどうかを確認
npm -v
#以下が表示
6.7.0

上記ような各バージョーンが表示されたらNode.jsのインストールが終わりします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

KubernetesとNode.jsでマイクロサービスを作成する 1/8

Node.jsとKubernetesを使い、マイクロサービスを作ってみたくなったので、このチュートリアルを作成してみました。
バグや修正した方がよい点などあれば気軽にコメントをおねがいします。

本チュートリアルは以下の8章構成になっています。

  • 第1章 概要
  • 第2章 Tweetサービス
  • 第3章 Userサービス
  • 第4章 Webサービス
  • 第5章 Docker
  • 第6章 Kubernetes with minikube
  • 第7章 Kubernetes with GCP
  • 第8章 Kubernetes with AWS

第1章 概要

この章では本チュートリアルの概要について記載します。

目的

本チュートリアルは以下の目的で作成されています。

  • Kubernetesを使い、実際にMicroserviceを構築することで、Kubernetesへの理解を深める
  • 複数チームによる開発を考慮し、リポジトリや検証環境を構築する
  • AWSのEKSとGCPのGKEを利用することで、PaaSでのKubernetes利用の知見を獲得する

作成するMicroserviceの概要

本チュートリアルではKubernetesとNode.jsを使い、TwitterライクなMicroserviceを構築します。

実装する機能としては下記になります。

  • ログイン/ログアウト機能(GitHub認証)
  • ツイート機能
  • フォロー/アンフォロー機能
  • タイムライン機能(自分 + フォローしているユーザーのツイート一覧)

構築するMicroserviceの概要図は下記のようになります。

BFF(Backend for Frontend)を採用し、Webサービスのサーバーサイドが各サービスとデータをやり取りする構成としています。

microservice-tutorial01.png

なお、Node.jsを採用した理由は下記のとおりです。

  • ミドルウェアなしに単一のプロセスで起動できること
    • Cloud Nativeなアプリケーションを作成する上で重要です
  • なるべくメジャーな言語であること
  • チュートリアル読者の実装ハードルを下げるため、各サービスとも共通した言語にしたい

各サービスについて

以下では、本チュートリアルで作成する3つのマイクロサービスについて説明します。

Webサービス

フロントエンド + BFFのサービスです。
ここでは、BFFはフロントエンドのチームが所有するものとしています。
GitHubを利用したOAuth2.0による認証機能を持ちます。

Userサービス

ユーザーやフォロー関係を扱うサービスです。
REST APIを各サービスへ提供します。

Tweetサービス

ツイートを扱うサービスです。
REST APIを各サービスへ提供します。

採用技術

本チュートリアルで作成するサンプルにおいて使用する主要な技術を列挙しておきます。
詳細は各サービスの章で説明します。

アーキテクチャ系

  • Microservice
    • 全体のアーキテクチャとして採用
  • BFF(Backend for Frontend)
    • フロントエンドと各サービスのAPI呼び出しパターンとして採用
  • REST API
    • サービス間通信のI/Fとして採用
  • MongoDB
    • NoSQLデータベース
    • Userサービス、Tweetサービスのデータベースとして採用

実装系

  • Node.js
    • 今回は全サービスの言語として採用
    • もちろん、Microserviceなので、各サービスで好きな言語を使用できる
  • Nuxt.js
    • Vue.jsを利用したSPA + SSRフレームワーク
    • WebサービスでUIフレームワークとして採用
  • Vuetify.js
    • Vue.js向けのマテリアルデザインライブラリ
    • UIの見た目をそれっぽくするためにNuxt.jsに組み込んで利用する
  • Express.js
    • Node.js製サーバーサイドのデファクトスタンダード
    • WebサービスのBFF部分やUserサービス、TweetサービスのREST APIサーバーとして利用
  • mongoose
    • Node.jsからMongoDBを利用するためのライブラリ
    • スキーマ定義も可能

第1章 まとめ

この章ではこれから作成するマイクロサービスの概要を紹介しました。
次の章からは実際に各サービスを作成していきます。

次章: 第2章 Tweetサービス

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.js&GraphQLの勉強 part1~基本操作~

GraphQLとは

簡単に言うとモダンなREST APIといったところ。
「クライアント ー REST API / GraphQL ー サーバー」のようにどちらもクライアントとサーバーの橋渡しをしている点と、HTTPメソッドで動く点は同じ。HTTPメソッドで動くということは、GraphQLもRest APIと同様にどのような言語/データベース/クライアントにも対応できるということ。

Rest API との違いは、一つのエンドポイントで好きなデータを問い合わせできるという点。欲しいデータに対してその都度エンドポイントを変える必要が無く、リクエストに対してクライアント側で多様な GraphQL query なるものをくっつけてやれば、それで取得データを決定することができる。

例)
・REST API ⇒ GET/posts/123 とか GET/posts?author=3421 とか
・GraphQL ⇒ POST/graphql (w/ a graphQL query) オンリー

これはつまり以下のように言える
・REST API ⇒ エンドポイントをもとにサーバーが必要なデータを決定する
・GraphQL ⇒ GraphQL queryを利用してクライアントが必要なデータを決定する

GraphQLの利点

1. 速い
GraphQL query の記述を変えればHTTPリクエスト1回で必要なデータをごっそりと取得できる ⇒ 速い

2.柔軟
GraphQL query の記述を変えるだけでエンドポイントを増やさずに取得するデータの量や種類を決定できる(モバイルには少量のデータを送るとか)

3.簡単
一つのエンドポイントしか管理しなくてよいから

Hello GraphQL

サーバー ⇒ クライアント で既存のデータを取得してみる

1 ) プロジェクトの初期化とBabelのインスト-ル

> npm init
> npm install babel-cli babel-preset-env
※ babel-cli:Babelのコンパイルに必要なコマンドを実行するのに必要
※ babel-preset-env:Babelに何をパースすべきか伝える

2 ) package.json / .babelrc / index.js を以下のように作成
キャプチャ.JPG
3 ) 「npm run start」 でコンパイルしてBabelの動作確認

> npm run start

> graphql@1.0.0 start C:\Users\xxx\Desktop\GraphQL\graphql
> babel-node src/index.js

hello

4 ) GraphQL Yogaのセットアップ

GraphQLはクエリがどのように働くかを決めているだけで実装そのものではない。
つまり、環境によってどのように実装するかを決めるのは開発者の仕事。

例えるなら、JavascriptがECMAスクリプトでどのように働くかを記述されており、そのJavaScriptを動かすためにChromeはV8エンジンを、MozillaはSpiderMonkeyを実装しているといった感じ。

ということで、今回はまずGraphQLがNodejs上で動くような環境作りから始める必要があり、そのために GraphQL Yoga を使用する。GraphQL Yoga は多機能&高性能&簡単で人気。

> npm i graphql-yoga

ダミーのデータをサーバーに準備しつつセットアップ。

index.js
import { GraphQLServer } from 'graphql-yoga';

// Type definition (Schema)
const typeDefs = `
    type Query { 
        hello: String!
        name: String!
    }
`

// Resolvers 
const resolvers = {
    Query : {
        hello() {
            return 'Hello GraphQL'
        },
        name() {
            return 'Hugo'
        }
    }
}

const server = new GraphQLServer({
    typeDefs,
    resolvers
})

server.start(() => {
    console.log('server is up');
})

  1. typeDefs でサポートする型を定義する(スキーマの定義)
  2. resolvers でクエリに対する処理を定義する
  3. serverのインスタンスを作成する
  4. serverを立ち上げる

※ TypeDefsは「クエリ名: 型!」で定義する(末尾の「!」が無い場合は null 可能ということ)

5 ) 実行

>npm run start
> graphql@1.0.0 start C:\Users\xxx\Desktop\GraphQL\graphql
> babel-node src/index.js

server is up

この状態で「localhost:4000」につなぐと GraphQL の Playground につながるので、クエリの実行と Hello GraphQL を確認する。
キャプチャ.JPG

6 ) ついでに Live Reload セットアップ
プロジェクトを保存する度にサーバーを自動でリロードするように設定する。

> npm install nodemon --save-dev

nodemonをインストールしたら package.json の scripts を以下のように書き変える。

package.json
  "scripts": {
    "start": "nodemon src/index.js --exec babel-node"
  }

index.jsを自動で実行しなおす、babel-nodeを通して。という意味になる。
これで「npm run start」を実行することで自動リロード状態になる。

GraphQL Types

【Scalar Type】

5つのビルトイン type が存在する。
1. ID: ユニークなid
2. String: 文字列
3. Int: 整数
4. Float: 小数
5. Boolean: true/false

ScalarType
// Type definition (Schema)
const typeDefs = `
    type Query { 
        id: ID!
        name: String!
        age: Int!
        height: Float!
     isAdult: Boolean!
    }
`

【Custom Type】

開発者が定義する type。

CustomType
// Type definition (Schema)
const typeDefs = `
    type Query { 
        me: User!
    }
    type User {
        id: ID!
        name: String!
        email: String!
        age: Int
    }
`

// Resolvers 
const resolvers = {
    Query : {
        me(){
            return {
                id: '12345',
                name: 'Hugo',
                email: 'hugo@example.com',
                age: 27
            }
        }
    }
}
`

※ クエリの形に注意
キャプチャ.JPG

Resolver Operation Arguments

index.js
// 引数に '!' が有る場合、その引数は required
const typeDefs = `
    type Query { 
        greeting(name: String, position: String): String!
        add(a:Float!, b:Float!): Float!
    }
`

const resolvers = {
    Query : {
        greeting(parent, args, ctx, info) {
            if(args.name && args.position) {
                return `Hello, ${args.name}! You are my favorite ${args.positino}`;
            } else {
                return 'Hello!'
            }
        },
        add(parent, args){
            return args.a + args.b
        }
    }
}

キャプチャ.JPG

Resolverには4つの引数が存在する

  1. parent : Type間にリレーションがある場合の親を指す
  2. args : operation arguments supplied
  3. ctx : contexutual data (ユーザの情報)
  4. info : サーバーに送信されたアクションの情報など

Array Type の扱い

【Arrays of Scalar types】

index.js
const typeDefs = `
    type Query { 
        add(numbers: [Float!]!): Float!
    }
`

const resolvers = {
    Query : {
        add(parent, args, ctx, info){
            if(args.numbers.length === 0 ) {
                return 0
            } 
            return args.numbers.reduce( ( accumulator, currentValue ) => accumulator + currentValue )

    }
}

キャプチャ.JPG

【Arrays of Custom types】

index.js
// Demo data
const users = [{
    id: '1',
    name: 'Hugo',
    email: 'hugo@ex.com',
    age: 27
}, {
    id: '2',
    name: 'Taro',
    email: 'taro@ex.com'
}, {
    id: '3',
    name: 'Aike',
    email: 'mike@ex.com'
}]

// Type definition (Schema)
const typeDefs = `
    type Query { 
        users(query: String): [User!]!
    }
    type User {
        id: ID!
        name: String!
        email: String!
        age: Int
    }
`

const resolvers = {
    Query : {
        users(parent, args, ctx, info) {
            if (!args.query){
                return users
            } else {
                return users.filter(user => user.name.toLowerCase().includes(args.query))
            }
        }
}

キャプチャ.JPG

Relation

Type の ID を追加することでリレーションが生まれる。

index.js
// Demo data
const users = [{
    id: '1',
    name: 'Hugo',
    email: 'hugo@ex.com',
    age: 27
}, {
    id: '2',
    name: 'Taro',
    email: 'taro@ex.com'
}, {
    id: '3',
    name: 'Aike',
    email: 'aike@ex.com'
}]
const posts = [{
    id: '4',
    title: 'aaa',
    body: 'asdtfhaer',
    published: true,
    author: '1'   /// 注目
}, {
    id: '5',
    title: 'fff',
    body: 'hrtea',
    published: true,
    author: '1'   /// 注目
}, {
    id: '6',
    title: 'Ahwerike',
    body: 'aikreshe',
    published: true,
    author: '2'   /// 注目
}]

const typeDefs = `
    type Query { 
        users(query: String): [User!]!
        posts(query: String): [Post!]!        
    }

    type User {
        id: ID!
        name: String!
        email: String!
        age: Int
        posts : [Post!]!  /// 注目
    }

    type Post {
        id: ID!
        title: String!
        body: String!
        published: Boolean!
        author: User!   /// 注目
    }
`

そして、Resolverにオブジェクトを追加することでクエリ時にリレーションをもつTypeを引きずってくることができる

index.js
const resolvers = {

    Query : {
        users(parent, args, ctx, info) {
            return users    // call posts() coded below (userの数だけcallする)
        },
        posts(parent, args, ctx, info) {
            return posts    // call author() coded below (postの数だけcallする)
        }
    },

    Post: {
        author(parent, args, ctx, info) {
            return users.find(user => user.id === parent.author) // parentはPost
       // 自分(Post)のauthor(UserのID)とマッチするUserを返却

        }
    },

    User: {
        posts(parent, args, ctx, info) {
            return posts.filter(post => post.author === parent.id) // parentはUser
       // 自分(User)のIDとマッチするauthorをもつPostを返却
        }
    }
}

キャプチャ.JPG

まとめ

index.js
import { GraphQLServer } from 'graphql-yoga';

// Demo data
// Arrayをフィールドに持ったりなんかしないですよ
const users = [{
    id: '1',
    name: 'Hugo',
    email: 'hugo@ex.com',
    age: 27,
}, {
    id: '2',
    name: 'Taro',
    email: 'taro@ex.com'
}, {
    id: '3',
    name: 'Aike',
    email: 'aike@ex.com'
}]

const posts = [{
    id: '4',
    title: 'About React',
    body: 'intriguing',
    published: true,
    author: '1' // userのID
}, {
    id: '5',
    title: 'About GraphQL',
    body: 'Im now studying',
    published: true,
    author: '1'
}, {
    id: '6',
    title: 'Money',
    body: 'very little',
    published: true,
    author: '2'
}]

const comments = [{
    id: '11',
    text: 'oh my god!',
    author: '1',  // userのID
    post: '4'    // postのID
}, {
    id: '21',
    text: 'jesus christ',
    author: '1',
    post: '4'
}, {
    id: '31',
    text: 'goo goo dloo l doo',
    author: '2',
    post: '5'
}, {
    id: '41',
    text: 'ironman',
    author: '3',
    post: '6'
}]


// Type definition (Schema)
const typeDefs = `
    type Query { 
        users(query: String): [User!]!
        posts(query: String): [Post!]!
        comments: [Comment!]!        
    }

    type User {
        id: ID!
        name: String!
        email: String!
        age: Int
        posts : [Post!]!
        comments: [Comment!]!
    }

    type Post {
        id: ID!
        title: String!
        body: String!
        published: Boolean!
        author: User!
        comments: [Comment!]!
    }

    type Comment {
        id: ID!
        text: String!
        author: User!
        posts: [Post!]!
    }
`

// Resolvers
const resolvers = {

    Query : {

        users(parent, args, ctx, info) {
            if (!args.query){
                return users
            } else {
                return users.filter(user => user.name.toLowerCase().includes(args.query.toLowerCase()))
            }
        },

        posts(parent, args, ctx, info) {
            if (!args.query){
                return posts    // call Post() coded below
            } else {
                return posts.filter(post => post.title.toLowerCase().includes(args.query))
            }
        },

        comments(parent, args, ctx, info){
            return comments
        }
    },

    Post: {
        author(parent, args, ctx, info) {
            return users.find(user => user.id === parent.author) // parentはPost
        },
        comments(parent, args, ctx, info){
            return comments.filter(comment => comment.post === parent.id)
        }
    },

    User: {
        posts(parent, args, ctx, info) {
            return posts.filter(post => post.author === parent.id) // parentはUser
        },
        comments(parent, args, ctx, info){
            return comments.filter(comment => comment.author === parent.id)
        }
    },

    Comment: {
        author(parent, args, ctx, info){
            return users.find(user => user.id === parent.author) // parentはComment
        },
        posts(parent, args, ctx, info){
            return posts.filter(post => post.id === parent.post);
        }
    }
}

const server = new GraphQLServer({
    typeDefs,
    resolvers
})

server.start(() => {
    console.log('server is up');
})

キャプチャ.JPG

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.js&GraphQL part1~基本操作~

GraphQLとは

簡単に言うとモダンなREST APIといったところ。
「クライアント ー REST API / GraphQL ー サーバー」のようにどちらもクライアントとサーバーの橋渡しをしている点と、HTTPメソッドで動く点は同じ。HTTPメソッドで動くということは、GraphQLもRest APIと同様にどのような言語/データベース/クライアントにも対応できるということ。

Rest API との違いは、一つのエンドポイントで好きなデータを問い合わせできるという点。欲しいデータに対してその都度エンドポイントを変える必要が無く、リクエストに対してクライアント側で多様な GraphQL query なるものをくっつけてやれば、それで取得データを決定することができる。

例)
・REST API ⇒ GET/posts/123 とか GET/posts?author=3421 とか
・GraphQL ⇒ POST/graphql (w/ a graphQL query) オンリー

これはつまり以下のように言える
・REST API ⇒ エンドポイントをもとにサーバーが必要なデータを決定する
・GraphQL ⇒ GraphQL queryを利用してクライアントが必要なデータを決定する

GraphQLの利点

1. 速い
GraphQL query の記述を変えればHTTPリクエスト1回で必要なデータをごっそりと取得できる ⇒ 速い

2.柔軟
GraphQL query の記述を変えるだけでエンドポイントを増やさずに取得するデータの量や種類を決定できる(モバイルには少量のデータを送るとか)

3.簡単
一つのエンドポイントしか管理しなくてよいから

Hello GraphQL

サーバー ⇒ クライアント で既存のデータを取得してみる

1 ) プロジェクトの初期化とBabelのインスト-ル

> npm init
> npm install babel-cli babel-preset-env
※ babel-cli:Babelのコンパイルに必要なコマンドを実行するのに必要
※ babel-preset-env:Babelに何をパースすべきか伝える

2 ) package.json / .babelrc / index.js を以下のように作成
キャプチャ.JPG
3 ) 「npm run start」 でコンパイルしてBabelの動作確認

> npm run start

> graphql@1.0.0 start C:\Users\xxx\Desktop\GraphQL\graphql
> babel-node src/index.js

hello

4 ) GraphQL Yogaのセットアップ

GraphQLはクエリがどのように働くかを決めているだけで実装そのものではない。
つまり、環境によってどのように実装するかを決めるのは開発者の仕事。

例えるなら、JavascriptがECMAスクリプトでどのように働くかを記述されており、そのJavaScriptを動かすためにChromeはV8エンジンを、MozillaはSpiderMonkeyを実装しているといった感じ。

ということで、今回はまずGraphQLがNodejs上で動くような環境作りから始める必要があり、そのために GraphQL Yoga を使用する。GraphQL Yoga は多機能&高性能&簡単で人気。

> npm i graphql-yoga

ダミーのデータをサーバーに準備しつつセットアップ。

index.js
import { GraphQLServer } from 'graphql-yoga';

// Type definition (Schema)
const typeDefs = `
    type Query { 
        hello: String!
        name: String!
    }
`

// Resolvers 
const resolvers = {
    Query : {
        hello() {
            return 'Hello GraphQL'
        },
        name() {
            return 'Hugo'
        }
    }
}

const server = new GraphQLServer({
    typeDefs,
    resolvers
})

server.start(() => {
    console.log('server is up');
})

  1. typeDefs でサポートする型を定義する(スキーマの定義)
  2. resolvers でクエリに対する処理を定義する
  3. serverのインスタンスを作成する
  4. serverを立ち上げる

※ TypeDefsは「クエリ名: 型!」で定義する(末尾の「!」が無い場合は null 可能ということ)

5 ) 実行

>npm run start
> graphql@1.0.0 start C:\Users\xxx\Desktop\GraphQL\graphql
> babel-node src/index.js

server is up

この状態で「localhost:4000」につなぐと GraphQL の Playground につながるので、クエリの実行と Hello GraphQL を確認する。
キャプチャ.JPG

6 ) ついでに Live Reload セットアップ
プロジェクトを保存する度にサーバーを自動でリロードするように設定する。

> npm install nodemon --save-dev

nodemonをインストールしたら package.json の scripts を以下のように書き変える。

package.json
  "scripts": {
    "start": "nodemon src/index.js --exec babel-node"
  }

index.jsを自動で実行しなおす、babel-nodeを通して。という意味になる。
これで「npm run start」を実行することで自動リロード状態になる。

GraphQL Types

【Scalar Type】

5つのビルトイン type が存在する。
1. ID: ユニークなid
2. String: 文字列
3. Int: 整数
4. Float: 小数
5. Boolean: true/false

ScalarType
// Type definition (Schema)
const typeDefs = `
    type Query { 
        id: ID!
        name: String!
        age: Int!
        height: Float!
     isAdult: Boolean!
    }
`

【Custom Type】

開発者が定義する type。

CustomType
// Type definition (Schema)
const typeDefs = `
    type Query { 
        me: User!
    }
    type User {
        id: ID!
        name: String!
        email: String!
        age: Int
    }
`

// Resolvers 
const resolvers = {
    Query : {
        me(){
            return {
                id: '12345',
                name: 'Hugo',
                email: 'hugo@example.com',
                age: 27
            }
        }
    }
}
`

※ クエリの形に注意
キャプチャ.JPG

Resolver Operation Arguments

index.js
// 引数に '!' が有る場合、その引数は required
const typeDefs = `
    type Query { 
        greeting(name: String, position: String): String!
        add(a:Float!, b:Float!): Float!
    }
`

const resolvers = {
    Query : {
        greeting(parent, args, ctx, info) {
            if(args.name && args.position) {
                return `Hello, ${args.name}! You are my favorite ${args.positino}`;
            } else {
                return 'Hello!'
            }
        },
        add(parent, args){
            return args.a + args.b
        }
    }
}

キャプチャ.JPG

Resolverには4つの引数が存在する

  1. parent : Type間にリレーションがある場合の親を指す
  2. args : operation arguments supplied
  3. ctx : contexutual data (ユーザの情報)
  4. info : サーバーに送信されたアクションの情報など

Array Type の扱い

【Arrays of Scalar types】

index.js
const typeDefs = `
    type Query { 
        add(numbers: [Float!]!): Float!
    }
`

const resolvers = {
    Query : {
        add(parent, args, ctx, info){
            if(args.numbers.length === 0 ) {
                return 0
            } 
            return args.numbers.reduce( ( accumulator, currentValue ) => accumulator + currentValue )

    }
}

キャプチャ.JPG

【Arrays of Custom types】

index.js
// Demo data
const users = [{
    id: '1',
    name: 'Hugo',
    email: 'hugo@ex.com',
    age: 27
}, {
    id: '2',
    name: 'Taro',
    email: 'taro@ex.com'
}, {
    id: '3',
    name: 'Aike',
    email: 'mike@ex.com'
}]

// Type definition (Schema)
const typeDefs = `
    type Query { 
        users(query: String): [User!]!
    }
    type User {
        id: ID!
        name: String!
        email: String!
        age: Int
    }
`

const resolvers = {
    Query : {
        users(parent, args, ctx, info) {
            if (!args.query){
                return users
            } else {
                return users.filter(user => user.name.toLowerCase().includes(args.query))
            }
        }
}

キャプチャ.JPG

Relation

Type の ID を追加することでリレーションが生まれる。

index.js
// Demo data
const users = [{
    id: '1',
    name: 'Hugo',
    email: 'hugo@ex.com',
    age: 27
}, {
    id: '2',
    name: 'Taro',
    email: 'taro@ex.com'
}, {
    id: '3',
    name: 'Aike',
    email: 'aike@ex.com'
}]
const posts = [{
    id: '4',
    title: 'aaa',
    body: 'asdtfhaer',
    published: true,
    author: '1'   /// 注目
}, {
    id: '5',
    title: 'fff',
    body: 'hrtea',
    published: true,
    author: '1'   /// 注目
}, {
    id: '6',
    title: 'Ahwerike',
    body: 'aikreshe',
    published: true,
    author: '2'   /// 注目
}]

const typeDefs = `
    type Query { 
        users(query: String): [User!]!
        posts(query: String): [Post!]!        
    }

    type User {
        id: ID!
        name: String!
        email: String!
        age: Int
        posts : [Post!]!  /// 注目
    }

    type Post {
        id: ID!
        title: String!
        body: String!
        published: Boolean!
        author: User!   /// 注目
    }
`

そして、Resolverにオブジェクトを追加することでクエリ時にリレーションをもつTypeを引きずってくることができる

index.js
const resolvers = {

    Query : {
        users(parent, args, ctx, info) {
            return users    // call posts() coded below (userの数だけcallする)
        },
        posts(parent, args, ctx, info) {
            return posts    // call author() coded below (postの数だけcallする)
        }
    },

    Post: {
        author(parent, args, ctx, info) {
            return users.find(user => user.id === parent.author) // parentはPost
       // 自分(Post)のauthor(UserのID)とマッチするUserを返却

        }
    },

    User: {
        posts(parent, args, ctx, info) {
            return posts.filter(post => post.author === parent.id) // parentはUser
       // 自分(User)のIDとマッチするauthorをもつPostを返却
        }
    }
}

キャプチャ.JPG

まとめ

index.js
import { GraphQLServer } from 'graphql-yoga';

// Demo data
// Arrayをフィールドに持ったりなんかしないですよ
const users = [{
    id: '1',
    name: 'Hugo',
    email: 'hugo@ex.com',
    age: 27,
}, {
    id: '2',
    name: 'Taro',
    email: 'taro@ex.com'
}, {
    id: '3',
    name: 'Aike',
    email: 'aike@ex.com'
}]

const posts = [{
    id: '4',
    title: 'About React',
    body: 'intriguing',
    published: true,
    author: '1' // userのID
}, {
    id: '5',
    title: 'About GraphQL',
    body: 'Im now studying',
    published: true,
    author: '1'
}, {
    id: '6',
    title: 'Money',
    body: 'very little',
    published: true,
    author: '2'
}]

const comments = [{
    id: '11',
    text: 'oh my god!',
    author: '1',  // userのID
    post: '4'    // postのID
}, {
    id: '21',
    text: 'jesus christ',
    author: '1',
    post: '4'
}, {
    id: '31',
    text: 'goo goo dloo l doo',
    author: '2',
    post: '5'
}, {
    id: '41',
    text: 'ironman',
    author: '3',
    post: '6'
}]


// Type definition (Schema)
const typeDefs = `
    type Query { 
        users(query: String): [User!]!
        posts(query: String): [Post!]!
        comments: [Comment!]!        
    }

    type User {
        id: ID!
        name: String!
        email: String!
        age: Int
        posts : [Post!]!
        comments: [Comment!]!
    }

    type Post {
        id: ID!
        title: String!
        body: String!
        published: Boolean!
        author: User!
        comments: [Comment!]!
    }

    type Comment {
        id: ID!
        text: String!
        author: User!
        posts: Post!
    }
`

// Resolvers
const resolvers = {

    Query : {

        users(parent, args, ctx, info) {
            if (!args.query){
                return users
            } else {
                return users.filter(user => user.name.toLowerCase().includes(args.query.toLowerCase()))
            }
        },

        posts(parent, args, ctx, info) {
            if (!args.query){
                return posts    // call Post() coded below
            } else {
                return posts.filter(post => post.title.toLowerCase().includes(args.query))
            }
        },

        comments(parent, args, ctx, info){
            return comments
        }
    },

    Post: {
        author(parent, args, ctx, info) {
            return users.find(user => user.id === parent.author) // parentはPost
        },
        comments(parent, args, ctx, info){
            return comments.filter(comment => comment.post === parent.id)
        }
    },

    User: {
        posts(parent, args, ctx, info) {
            return posts.filter(post => post.author === parent.id) // parentはUser
        },
        comments(parent, args, ctx, info){
            return comments.filter(comment => comment.author === parent.id)
        }
    },

    Comment: {
        author(parent, args, ctx, info){
            return users.find(user => user.id === parent.author) // parentはComment
        },
        posts(parent, args, ctx, info){
            return posts.filter(post => post.id === parent.post);
        }
    }
}

const server = new GraphQLServer({
    typeDefs,
    resolvers
})

server.start(() => {
    console.log('server is up');
})

キャプチャ.JPG

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

nodeでgoogle spreadsheetから値を取得する。

公式チュートリアルする

https://developers.google.com/sheets/api/quickstart/nodejs?hl=ja

https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit#gid=0
ここの値を取得するテスト。

Step 1: Turn on the Google Sheets API

credentials.jsonをダウンロードしておく
自身の持っているgoogleアカウントの認証情報を取得

Step 2: Install the client library

ライブラリを追加する

npm install googleapis@27 --save

Step 3: Set up the sample

Sampleコードをコピペする
sheets/quickstart/index.js

Step 4: Run the sample

node .

途中で

Authorize this app by visiting this url: https://accounts.google.com/o/oauth2/v2/auth?acce....

と聞かれる。

そのURLをクリックすると、Quickstartアプリへ、Googleスプレットシート表示権限が与えられる。
どういうことじゃ?
許可をクリックすると、トークンが表示される。
トークンを入力すると、spreadsheetの値が表示される。

自身の作ったSpreadsheetを参照する

spreadsheet_idとシート名を自身のspreadsheetに変えれば、動作する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む