サービス開発を加速させる技術選定 in Kibela


2017/07/18 Service Dev Meetup #1 

 Speee 



FUJI Goro / @__gfx__



: Ruby on Rails / TypeScript / React / GraphQL



 Kibela 

:

 RailsReactSSRReduxTypeScript




f:id:gfx:20170720100419p:plain



Kibela







Kibela



@gfx

















 





 :star2: :star2: 

 No!



Kibela

WYSIWIG editor vs plain text editor?











LINE BLOG contenteditable  : LINE Engineering Blog

contenteditableritch text editor使



KibelaFacebookDraftJS

DraftJS









DraftJSFacebook

Facebook



KibelaCodeMirror



GitHubCodeMirror



 SPA: Single Page Application



UX

UX > SPA

SPA



TypeScript



MicrosoftaltJS

JavaScript

TypeScript



TS  

Lint

TypeScript language-service 


f:id:gfx:20170720100454p:plain

RubyMine File object

TypeScript



TypeScript2012





ES 2015 TypeScript 2.0 2016

KibelaReact Redux

TypeScript



TypeScript

JavaScript





 any

e.g. TypeScript -  



 (@types/*) 使使

TSRails

Rails



Rails: wiki_path(blog)  "/wikis/42"

: wikis_path(page: 1, per: 20)  "/wikis?page=10&per=20"



JavaScript

: https://github.com/bitjourney/ts_routes-rails

import { wikisPath, wikiPath } as Routes from './generated/routes';

console.log(wikiPath(42)); // "/wikis/42"
console.log(wikisPath({ page: 1, per: 20 })); // "/wikis?page=1&per=20"




Rails



Railsdigest hash

: /assets/kibela_logo-f3e74a6f5c9f46cc4e8b920cb.svg



JavaScript

: https://github.com/bitjourney/ts_assets-rails

import * as React from 'react';
import { ImageRubyIcon } from './generated/assets';

class MyComponent extends React.Component<any, any> {
  render() {
    return (
      <ImageRubyIcon // for app/assets/images/ruby-icon.svg
        className='rubyLogo'
      />
    );
  }
}



GraphQL





React Native





GraphQL



Web API

Web API



GraphQL



REST Web API 



DBActiveRecordRails

Elasticsearch

association



 GitHub API v4 API console

https://developer.github.com/v4/explorer/



Incognito WindowChrome extension





Kibela

REST

GitHubFacebook使



: GitHub API v4


request:
query {  # トップレベルは必ず "query" または "mutation"
  viewer {  # ログインユーザから見れるデータで…

    # ログインユーザが管理するリポジトリの最初の3個をudpated_atでソートして
    repositories(first: 3, orderBy: { field: UPDATED_AT, direction: DESC }) {
      nodes { # data nodeのリスト
        name # リポジトリの名前をリクエストする
        description # リポジトリの説明をリクエストする
      }
    }
  }
}

response:
{
  "data": {
    "viewer": {
      "repositories": {
        "nodes": [
          {
            "name": "ts_routes-rails",
            "description": "Exports Rails URL helpers to TypeScript"
          },
          {
            "name": "rouge",
            "description": "A pure-ruby code highlighter"
          },
          {
            "name": "pygments.rb",
            "description": "pygments syntax highlighting in ruby"
          }
        ]
      }
    }
  }
}






API consoleGraphiQL 




f:id:gfx:20170720100517p:plain
f:id:gfx:20170720100532p:plain

GraphQL





RDBMSNoSQL

  RESTRDBMS

MongoDBHTTP interface :innocent:



Graph DB 

 N+1 REST

1 resource : 1 endpointREST N+1 

GraphQL



 REST

RESTRate-LimitGraphQL



gRPCRPC framework

GraphQL1







GraphQLRESTRPC framework




KibelaGraphQL pull-request

f:id:gfx:20170720100600p:plain
:
# トップレベルの "query" 型 (トップレベルはquery or mutation)
Types::QueryType = GraphQL::ObjectType.define do
  name "Query"

  # GraphQLは仕様としてdescriptionを書ける
  # descriptionはドキュメントビューアで使われる
  description "The query root of the schema"

  # 「blog」というリソースを宣言する
  field :blog do
    type Types::BlogType

    # blog リソースを取得するにはただひとつの必須引数idが必要
    argument :id, !types.ID

    resolve ->(_object, args, context) {
      # current_userがアクセス可能なblogをidで検索する
      # 戻り値はtypeで宣言したTypes::BlogTypeで宣言されたフィールドを持つ
      Blog.accessible_for(context[:current_user]).find_by!(id: args["id"])
    }
  end
end


ActiveRecordREST







 routes.rb JSON API

API / API / API

rate-limit



Q: GraphQLRESTAPI


GraphQLREST

REST= Rate LimitGraphQLRate LimitREST

N+1 REST APIN+1REST APIRESTGraphQL1

GraphQLRESTREST