{"id":1896,"date":"2019-05-13T19:52:16","date_gmt":"2019-05-13T10:52:16","guid":{"rendered":"https:\/\/lovelinux.mydns.jp\/?p=1896"},"modified":"2019-05-13T22:17:11","modified_gmt":"2019-05-13T13:17:11","slug":"apollo-server%e3%80%81graphql%e3%80%81nodejs%e3%80%81sequesize%e3%80%81%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%81%abreactredux%e3%81%a7-%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%e3%83%a1%e3%83%b3-2","status":"publish","type":"post","link":"https:\/\/lovelinux.mydns.jp\/?p=1896","title":{"rendered":"Apollo Server\u3001GraphQL\u3001nodejs\u3001sequesize\u3001\u30d5\u30ed\u30f3\u30c8\u306bReact+Redux\u3067 \u30de\u30b9\u30bf\u30fc\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u3092\u4f5c\u308d\u3046! \u301cVol.2"},"content":{"rendered":"<h3>\u524d\u56de\u306b\u7d9a\u3044\u3066<\/h3>\n<p>\u3068\u308a\u3042\u3048\u305a\u3001GraphQL\u3092\u5229\u7528\u3067\u304d\u308b Apollo Server\u304c\u8d77\u52d5\u3067\u304d\u305f\u306e\u3067\u3001<br \/>\nGraphQL\u3092\u4f7f\u3063\u3066\u3001\u5546\u54c1\u30c6\u30fc\u30d6\u30eb(products)\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u3066\u307f\u307e\u3057\u3087\u3046\u3002<\/p>\n<p>\u3053\u306e\u8a18\u4e8b\u306f\uff15\u56de\u306b\u5206\u3051\u3066\u9023\u8f09\u3059\u308b\u3001\u7b2c\uff12\u56de\u306e\u8a18\u4e8b\u3067\u3059\u3002<\/p>\n<p><font size=\"+1\"><\/p>\n<p><a href=\"https:\/\/lovelinux.mydns.jp\/?p=1867\">\u30fb\u7b2c\uff11\u56de Apollo Server\u304c\u52d5\u304f\u3068\u3053\u308d\u307e\u3067<\/a><\/p>\n<p><a href=\"https:\/\/lovelinux.mydns.jp\/?p=1896\">\u30fb\u7b2c\uff12\u56de Apollo Server\u914d\u4e0b\u3067\u3001GraphQL\u3092\u4f7f\u3063\u3066\u5546\u54c1\u30de\u30b9\u30bf\u30fc\u306b\u30a2\u30af\u30bb\u30b9\u3059\u308b\uff08\u3053\u306e\u8a18\u4e8b\uff09<\/a><\/p>\n<p><a href=\"https:\/\/lovelinux.mydns.jp\/?p=1905\">\u30fb\u7b2c\uff13\u56de \u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u3092React\uff0bRedux\uff0bgraphql-request\u3092\u4f7f\u3063\u3066\u5b9f\u88c5\u3059\u308b<\/a><\/p>\n<p><a href=\"https:\/\/lovelinux.mydns.jp\/?p=1909\">\u30fb\u7b2c\uff14\u56de \u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u304b\u3089graphql-request\u3092\u4f7f\u3063\u3066\u3001\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u30fb\u8868\u793a\u3059\u308b<\/a><\/p>\n<p><a href=\"https:\/\/lovelinux.mydns.jp\/?p=1920\">\u30fb\u7b2c\uff15\u56de graphql-request\u3092\u4f7f\u3063\u3066\u3001\u30c7\u30fc\u30bf\u3092\u767b\u9332\u30fb\u4fee\u6b63\u30fb\u524a\u9664\u3059\u308b<\/a><\/p>\n<p><\/font><\/p>\n<h3>\u5b8c\u6210\u30d5\u30a1\u30a4\u30eb\u30c4\u30ea\u30fc<\/h3>\n<p>\u8aac\u660e\u304c\u308f\u304b\u308a\u306b\u304f\u3044\u3068\u601d\u3046\u306e\u3067\u3001\u5b8c\u6210\u5f62\u306e\u30d5\u30a1\u30a4\u30eb\u30c4\u30ea\u30fc\u3092\u793a\u3057\u3066\u304a\u304d\u307e\u3059\u3002<br \/>\n<a href=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-59-59.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-59-59-1024x798.png\" alt=\"Screenshot from 2019-05-13 18-59-59\" width=\"806\" height=\"628\" class=\"alignnone size-large wp-image-1884\" srcset=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-59-59.png 1024w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-59-59-300x234.png 300w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-59-59-768x599.png 768w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/a><\/p>\n<h3>\u30c6\u30fc\u30d6\u30eb\u5b9a\u7fa9\uff08\u30b9\u30ad\u30fc\u30de\u4f5c\u6210\uff09<\/h3>\n<p>[bash]<br \/>\n$ mkdir datasources<\/p>\n<p>[\/bash]<\/p>\n<p>\u5546\u54c1\u30c6\u30fc\u30d6\u30eb\u306e\u69cb\u9020\u306f id\/\u5546\u54c1\u540d\/\u91d1\u984d\u3000\u3060\u3051\u306e\u30b7\u30f3\u30d7\u30eb\u306a\u3082\u306e\u306b\u3057\u307e\u3059\u3002<\/p>\n<p>[bash]<br \/>\n$ nano datasources\/create_table.sql<br \/>\n[\/bash]<\/p>\n<p>[bash]<br \/>\ncreate table products (<br \/>\n  id SERIAL,<br \/>\n  product_name TEXT,<br \/>\n  price INTEGER,<br \/>\n  &#8220;createdAt&#8221; timestamp with time zone,<br \/>\n  &#8220;updatedAt&#8221; timestamp with time zone,<br \/>\nprimary key (id));<\/p>\n<p>[\/bash]<\/p>\n<h3>\u30e2\u30c7\u30eb\u5b9a\u7fa9<\/h3>\n<p>\u5546\u54c1\u30c6\u30fc\u30d6\u30eb\u306e\u3000CRUD\u3092\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\uff08\u30e2\u30c7\u30eb\uff09\u306b\u5b9a\u7fa9\u3057\u307e\u3059\u3002<br \/>\n\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30a2\u30af\u30bb\u30b9\u306b\u306f sequelize\u3092\u4f7f\u3044\u307e\u3059\u306e\u3067\u3001\u305d\u306e\u4f7f\u3044\u65b9\u306f\u3001\u5404\u81ea\u5b66\u3093\u3067\u304f\u3060\u3055\u3044\u306d\u3002<br \/>\n\uff08\u3053\u306e\u7a0b\u5ea6\u3060\u3068\u3001\u30bd\u30fc\u30b9\u3092\u898b\u305f\u307e\u307e\u30b7\u30f3\u30d7\u30eb\u306a\u3082\u306e\u3067\u3059\u304c\u30fb\u30fb\u30fb\uff09<\/p>\n<p>[bash]<br \/>\n$ nano datasources\/product.js<br \/>\n[\/bash]<\/p>\n<p>[bash]<\/p>\n<p>import SQL from &#8220;sequelize&#8221;;<br \/>\nimport {DataSource } from &#8220;apollo-datasource&#8221;;<\/p>\n<p>class ProductAPI extends DataSource {<br \/>\n  constructor( {store} ) {<br \/>\n    super();<br \/>\n    this.store = store;<br \/>\n  }<\/p>\n<p>  initialize(config) {<br \/>\n    this.context = config.context;<br \/>\n  }<\/p>\n<p>  async add({product_name, price}) {<br \/>\n    return await this.store.products.create({product_name: product_name, price: price});<br \/>\n  }<\/p>\n<p>  async findOne({id}) {<br \/>\n    return await this.store.products.findByPk(id);<br \/>\n  }<\/p>\n<p>  async remove({id}) {<br \/>\n    const rec = await this.store.products.findByPk(id);<br \/>\n    const ret = await rec.destroy();<br \/>\n    return {id:0, product_name: &#8220;&#8221;, price: 0};<br \/>\n  }<\/p>\n<p>  async edit({id, product_name, price}){<br \/>\n    const rec = await this.store.products.findByPk(id);<br \/>\n    rec.product_name = product_name;<br \/>\n    rec.price = price;<br \/>\n    return await rec.save();<br \/>\n  }<\/p>\n<p>}<\/p>\n<p>export default ProductAPI;<\/p>\n<p>[\/bash]<\/p>\n<h3>index.js\u306e\u8abf\u6574<\/h3>\n<p>\u4f5c\u6210\u3057\u305f\u30e2\u30c7\u30eb\u3092\u4f7f\u3048\u308b\u3088\u3046\u306b\u3001\u4ee5\u4e0b\u306e\uff11\u884c\u3092\u8ffd\u8a18\u3057\u307e\u3059\u3002<\/p>\n<p>[bash]<br \/>\n$ nano index.js<br \/>\n[\/bash]<\/p>\n<p>[bash]<\/p>\n<p>const store = createStore();<\/p>\n<p>import ProductAPI from &#8220;.\/datasources\/product&#8221;;   <<<< \u3053\u306e\u884c\u3092\u8ffd\u8a18\n\n\nconst dataSources = () => ({<br \/>\n  productAPI: new ProductAPI({store}),<br \/>\n});<\/p>\n<p>[\/bash]<\/p>\n<h3>schema.js\u306bGraphQL API\u306e\u5b9a\u7fa9\u3092\u4f5c\u6210<\/h3>\n<p>\u3055\u3066\u3001\u3044\u3044\u52a0\u6e1b\u306b\u5b9a\u7fa9\u3057\u3066\u3044\u305f schema.js\u3092\u3061\u3083\u3093\u3068\u5b9f\u88c5\u3057\u307e\u3057\u3087\u3046\u3002<\/p>\n<p>id\u6307\u5b9a\u3057\u3066\u3001\uff11\u30ec\u30b3\u30fc\u30c9\u3092\u5f97\u308b \u300cgetProduct\u300d\u3000\u3068\u3001\u3000\u30e2\u30fc\u30c9\u6307\u5b9a\u3057\u3066<br \/>\n\u30c7\u30fc\u30bf\u306e\u767b\u9332\u30fb\u4fee\u6b63\u30fb\u524a\u9664\u3092\u884c\u3046 \u300cregisterProduct\u300d\u3092\u5b9a\u7fa9\u3057\u307e\u3057\u3087\u3046\u3002<\/p>\n<p>[bash]<br \/>\n$ nano schema.js<br \/>\n[\/bash]<\/p>\n<p>[bash]<\/p>\n<p>import { gql } from &#8220;apollo-server&#8221;;<\/p>\n<p>export default gql`<br \/>\n  scalar TimestampType<br \/>\n  type Query {<br \/>\n    getProduct(id: Int!): Product!<br \/>\n  }<\/p>\n<p>  type Mutation{<br \/>\n    registerProduct(mode: String!, id: Int!, product_name: String!, price: Int): Product!<br \/>\n  }<\/p>\n<p>  type Product {<br \/>\n    id: Int!<br \/>\n    product_name: String!<br \/>\n    price: Int!<br \/>\n  }<br \/>\n`;<br \/>\n[\/bash]<\/p>\n<h3>resolvers.js\u306bGraphQL API\u3092\u5b9f\u88c5<\/h3>\n<p>resolvers.js\u3000\u306b schema.js \u3067\u5b9a\u7fa9\u3057\u305f Query\u3068Mutation\u306e\u5b9f\u88c5\u3092\u3057\u307e\u3057\u3087\u3046\u3002<br \/>\n\u57fa\u672c\u306f\u3001product\u30e2\u30c7\u30eb\u306b\u4f5c\u6210\u3057\u305f\u30e1\u30bd\u30c3\u30c9\u3092\u547c\u3073\u51fa\u3057\u3066\u3044\u308b\u3060\u3051\u3067\u3059\u3002<\/p>\n<p>[bash]<br \/>\nimport { ForbiddenError } from &#8216;apollo-server&#8217;;<\/p>\n<p>export default {<br \/>\n  Query: {<br \/>\n    getProduct: async(_, {id}, {dataSources}) => {<br \/>\n      return await dataSources.productAPI.findOne({id})<br \/>\n    },<br \/>\n  },<\/p>\n<p>  Mutation: {<br \/>\n    registerProduct: async(_, {mode, id, product_name, price}, {dataSources}) => {<br \/>\n      let rec ;<br \/>\n      if (mode === &#8220;ADD&#8221;){<br \/>\n        rec = await dataSources.productAPI.add({product_name, price});<br \/>\n      }<br \/>\n      else if (mode === &#8220;EDIT&#8221;){<br \/>\n        rec = await dataSources.productAPI.edit({id, product_name, price});<br \/>\n      }<br \/>\n      else {<br \/>\n        rec = await dataSources.productAPI.remove({id});<br \/>\n      }<\/p>\n<p>      return rec;<br \/>\n    },<\/p>\n<p>  }<\/p>\n<p>}<\/p>\n<p>[\/bash]<\/p>\n<h3>\u5b9fDB \u306b create table<\/h3>\n<p>\u3044\u3056\u3001\u30ec\u30b3\u30fc\u30c9\u3092\u8ffd\u52a0\u3059\u308b\u524d\u306b Postgresql\u306b(mysql\u3067\u3082\u306a\u3093\u3067\u3082\u3044\u3044\u3067\u3059\u304c\u30fb\u30fb\u30fb\uff09<br \/>\nproducts \u30c6\u30fc\u30d6\u30eb\u3092 create table \u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n<p>[bash]<br \/>\ncreate table products (<br \/>\n  id SERIAL,<br \/>\n  product_name TEXT,<br \/>\n  price INTEGER,<br \/>\n  &#8220;createdAt&#8221; timestamp with time zone,<br \/>\n  &#8220;updatedAt&#8221; timestamp with time zone,<br \/>\nprimary key (id));<\/p>\n<p>[\/bash]<\/p>\n<h3>Apollo \u306e Playground\u3092\u4f7f\u3063\u3066\u3001\u30c7\u30fc\u30bf\u3092\u767b\u9332\u3057\u3066\u307f\u3088\u3046!<\/h3>\n<p>\u3067\u306f\u3001\u5b9f\u969b\u306b\u5148\u7a0b\u4f5c\u3063\u305f schema.js\u3068resolver.js\u3068 product.js\uff08\u30e2\u30c7\u30eb\uff09\u3092<br \/>\n\u4f7f\u3063\u3066\u3000\u30c7\u30fc\u30bf\u3092\u767b\u9332\u3057\u3066\u307f\u307e\u3057\u3087\u3046\uff01<\/p>\n<p>\u767b\u9332\u3059\u308b\u30c7\u30fc\u30bf\u306f<\/p>\n<pre>\r\n<code>\r\n\u5546\u54c1\u540d                \u4fa1\u683c\r\n----------------------------------\r\niPhone X Silver      87000\r\nGaraxy S10           72000\r\nFujitsu \u3089\u304f\u3089\u304f\u30db\u30f3  59000\r\n<\/code>\r\n<\/pre>\n<p>\u30d6\u30e9\u30a6\u30b6\u30fc\u3092\u8d77\u52d5\u3057\u3001http:\/\/localhost:4000\u3000\u3068\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br \/>\n\uff08\u305d\u306e\u524d\u306b npm start \u3082\u5fd8\u308c\u305a\u306b\uff09<\/p>\n<p>\u3053\u3093\u306a\u753b\u9762\u304c\u51fa\u308c\u3070OK\u3067\u3059\u3002<br \/>\n\u5de6\u5074\u306b\u3001 GraphQL\u8a00\u8a9e\u3067\u30af\u30a8\u30ea\u3092\u8a18\u8ff0\u3057\u3066\u3001\u771f\u3093\u4e2d\u306e\u4e09\u89d2\u30dc\u30bf\u30f3\u3067\u5b9f\u884c\u3059\u308b\u3068\u3001\u7d50\u679c\u304c\u53f3\u5074\u306b\u8868\u793a\u3055\u308c\u307e\u3059\u3002<\/p>\n<p><a href=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-51-01.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-51-01-1024x707.png\" alt=\"Screenshot from 2019-05-13 18-51-01\" width=\"806\" height=\"556\" class=\"alignnone size-large wp-image-1883\" srcset=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-51-01-1024x707.png 1024w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-51-01-300x207.png 300w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-51-01-768x530.png 768w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-13-18-51-01.png 1033w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/a><\/p>\n<h4>\u5546\u54c1\u30c7\u30fc\u30bf\u306e\u767b\u9332<\/h4>\n<p>\u4ee5\u4e0b\u306e\uff13\u3064\u306e\u30af\u30a8\u30ea\uff08mutation)\u3092\u5b9f\u884c\u3057\u30c7\u30fc\u30bf\u3092\u767b\u9332\u3057\u3066\u307f\u307e\u3057\u3087\u3046\u3002<br \/>\n[bash]<br \/>\nmutation RegisterProduct {<br \/>\n  registerProduct(mode: &#8220;ADD&#8221;, id:0, product_name: &#8220;iPhone X Silver&#8221;, price: 87000){<br \/>\n    id<br \/>\n  }<br \/>\n}<br \/>\n[\/bash]<\/p>\n<p>[bash]<br \/>\nmutation RegisterProduct {<br \/>\n  registerProduct(mode: &#8220;ADD&#8221;, id:0, product_name: &#8220;Garaxy S10&#8221;, price: 72000){<br \/>\n    id<br \/>\n  }<br \/>\n}<\/p>\n<p>[\/bash]<\/p>\n<p>[bash]<br \/>\nmutation RegisterProduct {<br \/>\n  registerProduct(mode: &#8220;ADD&#8221;, id:0, product_name: &#8220;Fujitsu \u3089\u304f\u3089\u304f\u30db\u30f3&#8221;, price: 59000){<br \/>\n    id<br \/>\n  }<br \/>\n}<br \/>\n[\/bash]<\/p>\n<p><a href=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-33.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-33-1024x763.png\" alt=\"Screenshot from 2019-05-12 21-57-33\" width=\"806\" height=\"601\" class=\"alignnone size-large wp-image-1874\" srcset=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-33-1024x763.png 1024w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-33-300x224.png 300w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-33-768x572.png 768w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-33.png 1052w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/a><\/p>\n<h4>\u5546\u54c1\u30c7\u30fc\u30bf\u306e\u4fee\u6b63<\/h4>\n<p>\u3067\u306f\u3001iPhone\u306e\u4fa1\u683c\u3092\u30a2\u30c3\u30d7\u3057\u3066\u307f\u307e\u3057\u3087\u3046<\/p>\n<p>[bash]<br \/>\nmutation RegisterProduct {<br \/>\n  registerProduct(mode: &#8220;EDIT&#8221;, id:1, product_name: &#8220;iPhone X Silver&#8221;, price: 93000){<br \/>\n    id<br \/>\n  }<br \/>\n}<br \/>\n[\/bash]<\/p>\n<p><a href=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-25.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-25-1024x763.png\" alt=\"Screenshot from 2019-05-12 21-57-25\" width=\"806\" height=\"601\" class=\"alignnone size-large wp-image-1873\" srcset=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-25-1024x763.png 1024w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-25-300x224.png 300w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-25-768x572.png 768w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-21-57-25.png 1052w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/a><\/p>\n<h4>\u5546\u54c1\u30c7\u30fc\u30bf\u306e\u8aad\u307f\u8fbc\u307f<\/h4>\n<p>\u30c7\u30fc\u30bf\u306f ID\uff1d1\u301c3 \u3067\u3067\u304d\u3066\u3044\u308b\u306e\u3067\u3001Query\u3092\u4f7f\u3063\u3066\u3001\u30c7\u30fc\u30bf\u3092\u30ea\u30fc\u30c9\u3057\u3066\u307f\u307e\u3057\u3087\u3046<\/p>\n<p>[bash]<br \/>\nquery GetProduct{<br \/>\n  getProduct(id: 2){<br \/>\n    id<br \/>\n    product_name<br \/>\n    price<br \/>\n  }<br \/>\n}<\/p>\n<p>[\/bash]<\/p>\n<p><a href=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-00-16.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-00-16-1024x763.png\" alt=\"Screenshot from 2019-05-12 22-00-16\" width=\"806\" height=\"601\" class=\"alignnone size-large wp-image-1875\" srcset=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-00-16-1024x763.png 1024w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-00-16-300x224.png 300w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-00-16-768x572.png 768w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-00-16.png 1052w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/a><\/p>\n<h4>\u5546\u54c1\u30c7\u30fc\u30bf\u3092N\u4ef6\u30ea\u30fc\u30c9\u3059\u308b<\/h4>\n<p>1\u4ef6\u306e\u30c7\u30fc\u30bf\u306f\u53d6\u5f97\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u305f\u306e\u3067\u3001\u4eca\u5ea6\u306fproducts\u30c6\u30fc\u30d6\u30eb\u306eN\u4ef6\u306e\u30ec\u30b3\u30fc\u30c9\u3092\u53d6\u5f97\u3059\u308b<br \/>\nQuery\u3092\u5b9a\u7fa9\u3057\u3066\u307f\u307e\u3057\u3087\u3046\u3002(getProducts)<br \/>\n\u623b\u308a\u5024\u306f ProductConnection  \u3067\u3001\u305d\u306e\u4e2d\u306b Product\u578b\u3068Boolean\u578b\u306ehas_more\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n<p>[bash]<br \/>\n$ nano schema.js<\/p>\n<p>[\/bash]<\/p>\n<p>[bash]<br \/>\nimport { gql } from &#8220;apollo-server&#8221;;<br \/>\nimport TimestampType from &#8220;.\/GraphQLTimestamp&#8221;;<\/p>\n<p>export default gql`<br \/>\n  scalar TimestampType<br \/>\n  type Query {<br \/>\n    getProduct(id: Int!): Product!<br \/>\n    getProducts(offset: Int!, limit: Int!): ProductConnection!<br \/>\n  }<\/p>\n<p>  type Mutation{<br \/>\n    registerProduct(mode: String!, id: Int!, product_name: String!, price: Int): Product!<br \/>\n  }<\/p>\n<p>  type Product {<br \/>\n    id: Int!<br \/>\n    product_name: String!<br \/>\n    price: Int!<br \/>\n  }<\/p>\n<p>  type ProductConnection {<br \/>\n    products: [Product!]<br \/>\n    has_more: Boolean!<br \/>\n  }<br \/>\n`;<\/p>\n<p>[\/bash]<\/p>\n<p>[bash]<br \/>\n$ nano resolvers.js<br \/>\n[\/bash]<\/p>\n<p>[bash]<br \/>\nimport { ForbiddenError } from &#8216;apollo-server&#8217;;<\/p>\n<p>export default {<br \/>\n  Query: {<br \/>\n    getProduct: async(_, {id}, {dataSources}) => {<br \/>\n      return await dataSources.productAPI.findOne({id})<br \/>\n    },<br \/>\n    getProducts: async(_, {offset, limit}, {dataSources}) => {<br \/>\n      return await dataSources.productAPI.findForList({offset, limit})<br \/>\n    },<br \/>\n  },<\/p>\n<p>  Mutation: {<br \/>\n    registerProduct: async(_, {mode, id, product_name, price}, {dataSources}) => {<br \/>\n      let rec ;<br \/>\n      if (mode === &#8220;ADD&#8221;){<br \/>\n        rec = await dataSources.productAPI.add({product_name, price});<br \/>\n      }<br \/>\n      else if (mode === &#8220;EDIT&#8221;){<br \/>\n        rec = await dataSources.productAPI.edit({id, product_name, price});<br \/>\n      }<br \/>\n      else {<br \/>\n        rec = await dataSources.productAPI.remove({id});<br \/>\n      }<\/p>\n<p>      return rec;<br \/>\n    },<\/p>\n<p>  }<\/p>\n<p>}<\/p>\n<p>[\/bash]<\/p>\n<p>\u30e2\u30c7\u30eb\u306b\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u304b\u3089\u30c7\u30fc\u30bf\u3092\u53d6\u3063\u3066\u304f\u308b\u30ed\u30b8\u30c3\u30af\u3092\u5b9f\u88c5\u3057\u307e\u3059\u3002<\/p>\n<p>[bash]<br \/>\n$ nano datasources\/product.js<br \/>\n[\/bash]<\/p>\n<p>[bash]<br \/>\n  async findForList({offset, limit}){<br \/>\n    const recs = await this.store.products.findAll({<br \/>\n      offset: offset,<br \/>\n      limit: limit,<br \/>\n    });<\/p>\n<p>    let has_more = false;<br \/>\n    if (recs.length === limit){<br \/>\n      has_more = true;<br \/>\n    }<\/p>\n<p>    return {products: recs, has_more: has_more};<br \/>\n  }<br \/>\n[\/bash]<\/p>\n<h3>Playground\u3067\u30c7\u30fc\u30bf\u3092N\u4ef6\u53d6\u5f97\u3057\u3066\u307f\u308b<\/h3>\n<p>\u3053\u3093\u306a\u611f\u3058\u306b\u8868\u793a\u3055\u308c\u308c\u3070\u3001\u6210\u529f\u3067\u3059\u3002<br \/>\n[bash]<br \/>\nquery GetProducts {<br \/>\n  getProducts(offset:0 , limit:20){<br \/>\n    products{<br \/>\n      id<br \/>\n      product_name<br \/>\n      price<br \/>\n    }<br \/>\n    has_more<br \/>\n  }<br \/>\n}<br \/>\n[\/bash]<\/p>\n<p><a href=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-12-17.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-12-17-1024x788.png\" alt=\"Screenshot from 2019-05-12 22-12-17\" width=\"806\" height=\"620\" class=\"alignnone size-large wp-image-1876\" srcset=\"https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-12-17-1024x788.png 1024w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-12-17-300x231.png 300w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-12-17-768x591.png 768w, https:\/\/lovelinux.mydns.jp\/wp-content\/uploads\/2019\/05\/Screenshot-from-2019-05-12-22-12-17.png 1231w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/a><\/p>\n<p>\u3053\u308c\u3067CRUD\u3068\u4e00\u89a7\u53d6\u5f97API\u304c\u3067\u304d\u305f\u306e\u3067\u3001\u6b21\u56de\u306f\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u5074\u306e\u5b9f\u88c5\u306b\u3064\u3044\u3066<br \/>\n\u8a18\u8ff0\u3092\u958b\u59cb\u3057\u307e\u3059\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u524d\u56de\u306b\u7d9a\u3044\u3066 \u3068\u308a\u3042\u3048\u305a\u3001GraphQL\u3092\u5229\u7528\u3067\u304d\u308b Apollo Server\u304c\u8d77\u52d5\u3067\u304d\u305f\u306e\u3067\u3001 GraphQL\u3092\u4f7f\u3063\u3066\u3001\u5546\u54c1\u30c6\u30fc\u30d6\u30eb(products)\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u3066\u307f\u307e\u3057\u3087\u3046\u3002 \u3053\u306e\u8a18\u4e8b\u306f\uff15\u56de\u306b\u5206\u3051\u3066\u9023\u8f09\u3059\u308b\u3001\u7b2c\uff12\u56de\u306e\u8a18\u4e8b\u3067\u3059\u3002 \u30fb\u7b2c\uff11\u56de Apollo Server\u304c\u52d5\u304f\u3068\u3053\u308d\u307e\u3067 \u30fb\u7b2c\uff12\u56de Apollo Server\u914d\u4e0b\u3067\u3001GraphQL\u3092\u4f7f\u3063\u3066\u5546\u54c1\u30de\u30b9\u30bf\u30fc\u306b\u30a2\u30af\u30bb\u30b9\u3059\u308b\uff08\u3053\u306e\u8a18\u4e8b\uff09 \u30fb\u7b2c\uff13\u56de \u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u3092React\uff0bRedux\uff0bgraphql-request\u3092\u4f7f\u3063\u3066\u5b9f\u88c5\u3059\u308b \u30fb\u7b2c\uff14\u56de \u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u304b\u3089graphql-request\u3092\u4f7f\u3063\u3066\u3001\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u30fb\u8868\u793a\u3059\u308b \u30fb\u7b2c\uff15\u56de graphql-request\u3092\u4f7f\u3063\u3066\u3001\u30c7\u30fc\u30bf\u3092\u767b\u9332\u30fb\u4fee\u6b63\u30fb\u524a\u9664\u3059\u308b \u5b8c\u6210\u30d5\u30a1\u30a4\u30eb\u30c4\u30ea\u30fc \u8aac\u660e\u304c\u308f\u304b\u308a\u306b\u304f\u3044\u3068\u601d\u3046\u306e\u3067\u3001\u5b8c\u6210\u5f62\u306e\u30d5\u30a1\u30a4\u30eb\u30c4\u30ea\u30fc\u3092\u793a\u3057\u3066\u304a\u304d\u307e\u3059\u3002 \u30c6\u30fc\u30d6\u30eb\u5b9a\u7fa9\uff08\u30b9\u30ad\u30fc\u30de\u4f5c\u6210\uff09 [bash] $ mkdir datasources [\/bash] \u5546\u54c1\u30c6\u30fc\u30d6\u30eb\u306e\u69cb\u9020\u306f id\/\u5546\u54c1\u540d\/\u91d1\u984d\u3000\u3060\u3051\u306e\u30b7\u30f3\u30d7\u30eb\u306a\u3082\u306e\u306b\u3057\u307e\u3059\u3002 [bash] $ nano datasources\/create_table.sql [\/bash] [bash] create table products ( id SERIAL, product_name TEXT, price INTEGER, &#8220;createdAt&#8221; timestamp with time zone, &#8220;updatedAt&#8221; timestamp with time zone, primary key (id)); [\/bash] \u30e2\u30c7\u30eb\u5b9a\u7fa9 \u5546\u54c1\u30c6\u30fc\u30d6\u30eb\u306e\u3000CRUD\u3092\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\uff08\u30e2\u30c7\u30eb\uff09\u306b\u5b9a\u7fa9\u3057\u307e\u3059\u3002 \u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30a2\u30af\u30bb\u30b9\u306b\u306f sequelize\u3092\u4f7f\u3044\u307e\u3059\u306e\u3067\u3001\u305d\u306e\u4f7f\u3044\u65b9\u306f\u3001\u5404\u81ea\u5b66\u3093\u3067\u304f\u3060\u3055\u3044\u306d\u3002 \uff08\u3053\u306e\u7a0b\u5ea6\u3060\u3068\u3001\u30bd\u30fc\u30b9\u3092\u898b\u305f\u307e\u307e\u30b7\u30f3\u30d7\u30eb\u306a\u3082\u306e\u3067\u3059\u304c\u30fb\u30fb\u30fb\uff09 [bash] $ nano datasources\/product.js [\/bash] [bash] import SQL from &#8220;sequelize&#8221;; import {DataSource } from &#8220;apollo-datasource&#8221;; class ProductAPI extends DataSource { constructor( {store} ) { super(); this.store = store; } initialize(config) { this.context = config.context; } async add({product_name, price}) { return await this.store.products.create({product_name: product_name, price: price}); } async findOne({id}) { return await this.store.products.findByPk(id); } async remove({id}) { const rec = await this.store.products.findByPk(id); const ret = await rec.destroy(); return {id:0, product_name: &#8220;&#8221;, price: 0}; } async edit({id, product_name, price}){ const rec = await this.store.products.findByPk(id); rec.product_name = product_name; rec.price = price; return await rec.save(); } } export default ProductAPI; [\/bash] index.js\u306e\u8abf\u6574 \u4f5c\u6210\u3057\u305f\u30e2\u30c7\u30eb\u3092\u4f7f\u3048\u308b\u3088\u3046\u306b\u3001\u4ee5\u4e0b\u306e\uff11\u884c\u3092\u8ffd\u8a18\u3057\u307e\u3059\u3002 [bash] $ nano index.js [\/bash] [bash] const store = createStore(); import ProductAPI from &#8220;.\/datasources\/product&#8221;; { let rec ; if (mode === &#8220;ADD&#8221;){ rec = await dataSources.productAPI.add({product_name, price}); } else if (mode === &#8220;EDIT&#8221;){ rec = await dataSources.productAPI.edit({id, product_name, price}); } else { rec = await dataSources.productAPI.remove({id}); } return rec; }, } } [\/bash] \u5b9fDB \u306b create table \u3044\u3056\u3001\u30ec\u30b3\u30fc\u30c9\u3092\u8ffd\u52a0\u3059\u308b\u524d\u306b Postgresql\u306b(mysql\u3067\u3082\u306a\u3093\u3067\u3082\u3044\u3044\u3067\u3059\u304c\u30fb\u30fb\u30fb\uff09 products \u30c6\u30fc\u30d6\u30eb\u3092 create table \u3057\u3066\u304f\u3060\u3055\u3044\u3002 [bash] create table products ( id SERIAL, product_name TEXT, price INTEGER, &#8220;createdAt&#8221; timestamp with time zone, &#8220;updatedAt&#8221; timestamp with time zone, primary key (id)); [\/bash] Apollo \u306e Playground\u3092\u4f7f\u3063\u3066\u3001\u30c7\u30fc\u30bf\u3092\u767b\u9332\u3057\u3066\u307f\u3088\u3046! \u3067\u306f\u3001\u5b9f\u969b\u306b\u5148\u7a0b\u4f5c\u3063\u305f schema.js\u3068resolver.js\u3068 product.js\uff08\u30e2\u30c7\u30eb\uff09\u3092 \u4f7f\u3063\u3066\u3000\u30c7\u30fc\u30bf\u3092\u767b\u9332\u3057\u3066\u307f\u307e\u3057\u3087\u3046\uff01 \u767b\u9332\u3059\u308b\u30c7\u30fc\u30bf\u306f \u5546\u54c1\u540d \u4fa1\u683c &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- iPhone X Silver 87000 Garaxy S10 72000 Fujitsu \u3089\u304f\u3089\u304f\u30db\u30f3 59000 \u30d6\u30e9\u30a6\u30b6\u30fc\u3092\u8d77\u52d5\u3057\u3001http:\/\/localhost:4000\u3000\u3068\u3057\u3066\u304f\u3060\u3055\u3044\u3002 \uff08\u305d\u306e\u524d\u306b npm start \u3082\u5fd8\u308c\u305a\u306b\uff09 \u3053\u3093\u306a\u753b\u9762\u304c\u51fa\u308c\u3070OK\u3067\u3059\u3002 \u5de6\u5074\u306b\u3001 GraphQL\u8a00\u8a9e\u3067\u30af\u30a8\u30ea\u3092\u8a18\u8ff0\u3057\u3066\u3001\u771f\u3093\u4e2d\u306e\u4e09\u89d2\u30dc\u30bf\u30f3\u3067\u5b9f\u884c\u3059\u308b\u3068\u3001\u7d50\u679c\u304c\u53f3\u5074\u306b\u8868\u793a\u3055\u308c\u307e\u3059\u3002 \u5546\u54c1\u30c7\u30fc\u30bf\u306e\u767b\u9332 \u4ee5\u4e0b\u306e\uff13\u3064\u306e\u30af\u30a8\u30ea\uff08mutation)\u3092\u5b9f\u884c\u3057\u30c7\u30fc\u30bf\u3092\u767b\u9332\u3057\u3066\u307f\u307e\u3057\u3087\u3046\u3002 [bash] mutation RegisterProduct { registerProduct(mode: &#8220;ADD&#8221;, id:0, product_name: &#8220;iPhone X Silver&#8221;, price: 87000){ id } } [\/bash] [bash]&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[77],"tags":[102,101,86],"class_list":{"0":"post-1896","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-react","7":"tag-apollo","8":"tag-graphql","9":"tag-react"},"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/lovelinux.mydns.jp\/index.php?rest_route=\/wp\/v2\/posts\/1896","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lovelinux.mydns.jp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lovelinux.mydns.jp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lovelinux.mydns.jp\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lovelinux.mydns.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1896"}],"version-history":[{"count":10,"href":"https:\/\/lovelinux.mydns.jp\/index.php?rest_route=\/wp\/v2\/posts\/1896\/revisions"}],"predecessor-version":[{"id":1938,"href":"https:\/\/lovelinux.mydns.jp\/index.php?rest_route=\/wp\/v2\/posts\/1896\/revisions\/1938"}],"wp:attachment":[{"href":"https:\/\/lovelinux.mydns.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1896"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lovelinux.mydns.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1896"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lovelinux.mydns.jp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1896"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}