Skip to content

Instantly share code, notes, and snippets.

@amarg26
Forked from ahandsel/00_React_Workshop_v3.md
Created September 26, 2021 14:02
Show Gist options
  • Save amarg26/bcca1dcbf0e9699110ad7f33ca2fb22a to your computer and use it in GitHub Desktop.
Save amarg26/bcca1dcbf0e9699110ad7f33ca2fb22a to your computer and use it in GitHub Desktop.

Revisions

  1. @ahandsel ahandsel revised this gist Aug 19, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions 00_React_Workshop_v3.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    <!-- 00_React_Workshop_v2.md -->
    # React & REST API Workshop Part 2
    <!-- 00_React_Workshop_v3.md -->
    # React & REST API Workshop Version 3

    ## Let's POST Data to a Web Database From a React Component

  2. @ahandsel ahandsel revised this gist Aug 19, 2021. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -1,2 +0,0 @@

    .DS_Store
  3. @ahandsel ahandsel revised this gist Aug 19, 2021. 13 changed files with 1051 additions and 1 deletion.
    2 changes: 2 additions & 0 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,2 @@

    .DS_Store
    88 changes: 88 additions & 0 deletions 00_React_Workshop_v3.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,88 @@
    <!-- 00_React_Workshop_v2.md -->
    # React & REST API Workshop Part 2

    ## Let's POST Data to a Web Database From a React Component

    Thank you for attending our 2nd **Kintone x React** workshop!
    Use the following files to follow along!

    ### Download Links
    Click [**here**](https://gist.github.com/ahandsel/556e42aad59ff22604a9042174c556bc/archive/master.zip) or the ![Download Zip](https://user-images.githubusercontent.com/30670749/92357094-3e063e00-f122-11ea-8003-0307587e2c15.png) button on the upper right corner for all the code & slides you need for our workshop!

    ---

    ## Outline
    * [📎 PREREQUISITE](#-prerequisite)
    * [💾 Install Node & npm](#-install-node--npm)
    * [🕹️ Install a Sample React App](#️-install-a-sample-react-app)
    * [🚀 Getting your FREE Kintone Database](#-getting-your-free-kintone-database)
    * [📺 Quick Videos Going Over the Prep Work](#-quick-videos-going-over-the-prep-work)
    * [📚 Suggested Reading](#-suggested-reading)
    * [Details at dev.to](#details-at-devto)
    * [Overview of the Workshop](#overview-of-the-workshop)

    ---

    ## 📎 PREREQUISITE

    ### 💾 Install Node & npm
    * Node ≥ 10.16 and npm ≥ 5.6 are required for this workshop
    * Confused? 🤔 → Check out the [Video Guides](#-quick-videos-going-over-the-prep-work)

    ### 🕹️ Install a Sample React App
    * Create a `myproject` folder
    * We will be starting from the publicly available [sample React App](https://create-react-app.dev/).
    * Confused? 🤔 → Check out the [Video Guides](#-quick-videos-going-over-the-prep-work)

    ### 🚀 Getting your FREE Kintone Database

    #### ① Sign-Up for Developer Program Account (Website) 🌐
    * [bit.ly/KDP_signup](https://bit.ly/KDP_signup)
    * ⚠ Do NOT use Safari
    * ⚡Accept Cookies First
    * ✅ Use Chrome & Firefox

    #### ② THEN Create a Kintone Subdomain (Database) 📂
    * [bit.ly/K_DevLic](http://bit.ly/K_DevLic)
    * ⚡ Only use lowercase, numbers, & hyphens in your subdomain
    * ⚠ Do not use uppercase nor special characters

    Confused? 🤔 → Check out the [Video Guides](#-quick-videos-going-over-the-prep-work)

    ---

    ### 📺 Quick Videos Going Over the Prep Work

    | Install Node & Sample React App | Signing Up for Kintone |
    | ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
    | [![https://youtu.be/4Kw-i_rX3tY](https://img.youtube.com/vi/4Kw-i_rX3tY/mq1.jpg)](https://youtu.be/4Kw-i_rX3tY) <https://youtu.be/4Kw-i_rX3tY> | [![https://youtu.be/Gzz8SbTuoFg](https://img.youtube.com/vi/Gzz8SbTuoFg/mq1.jpg)](https://youtu.be/Gzz8SbTuoFg) <https://youtu.be/Gzz8SbTuoFg> |

    ---

    ## 📚 Suggested Reading
    We advise you to have a look through the following React documents beforehand:
    1. [Hello World](https://reactjs.org/docs/hello-world.html)
    2. [Introducing JSX](https://reactjs.org/docs/introducing-jsx.html)
    3. [Rendering Elements](https://reactjs.org/docs/rendering-elements.html)
    4. [Components and Props](https://reactjs.org/docs/components-and-props.html)

    ## Details at [dev.to](https://dev.to/will_yama/series/11707)

    [![React & REST API Series' Articles](https://user-images.githubusercontent.com/30670749/111263228-ddbffe00-8668-11eb-9550-f42944f45c76.png)](https://dev.to/will_yama/series/11707)

    Check out Will's [React & REST API Series' Articles](https://dev.to/will_yama/series/11707) at [dev.to](https://dev.to/will_yama/series/11707) Community 👩‍💻👨‍💻!

    ---

    ## Overview of the Workshop

    | Parts | Type | Description |
    | ------------------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------ |
    | [Prep](https://gist.github.com/ahandsel/813e642bf36008192708c50a23185935#file-01_prep-md) | Setup Guide | Everything you need to do before the workshop |
    | [Part A](https://gist.github.com/ahandsel/813e642bf36008192708c50a23185935#file-a_promiseerror_demo-md) | Demo | Quick demo using promises in React |
    | [Part B](https://gist.github.com/ahandsel/813e642bf36008192708c50a23185935#file-b_hooks-md) | **Live Coding** | Let's use `useState` & `useEffect` Hooks instead |
    | [Part C](https://gist.github.com/ahandsel/813e642bf36008192708c50a23185935#file-c_kintonedatabase-md) | Setup Guide | Create a Kintone account & a database app |
    | [Part D](https://gist.github.com/ahandsel/813e642bf36008192708c50a23185935#file-d_cors_error_demo-md) | Demo | Quick demo that results in CORS error |
    | [Part E](https://gist.github.com/ahandsel/813e642bf36008192708c50a23185935#file-e_expressserver-md) | Setup Guide | Let's install the *backend* Express server |
    | [Part F](https://gist.github.com/ahandsel/813e642bf36008192708c50a23185935#file-f_get_data-md) | Demo | Getting data from the Kintone App |
    | [Part G](https://gist.github.com/ahandsel/813e642bf36008192708c50a23185935#file-g_post_data-md) | **Live Coding** | Posting data to the Kintone App |
    1 change: 0 additions & 1 deletion 00_React_Workshop_v3_Test.md
    Original file line number Diff line number Diff line change
    @@ -1 +0,0 @@
    _
    179 changes: 179 additions & 0 deletions 01_Prep.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,179 @@
    # Prepping for React Workshop
    This is a step-by-step guide that will go over everything you need to do before our workshop in detail!
    Let's get started!

    **Outline**:
    * [1. Create a `myproject` folder](#1-create-a-myproject-folder)
    * [Check if you already have Node.js or npm](#check-if-you-already-have-nodejs-or-npm)
    * [2. Install Node.js](#2-install-nodejs)
    * [macOS with nodenv](#macos-with-nodenv)
    * [Windows with nvm-windows](#windows-with-nvm-windows)
    * [3. Install a Sample React App](#3-install-a-sample-react-app)
    * [⚠️ Got an error?](#️-got-an-error)
    * [📺 YouTube Quick Videos Going Over the Node Install & Create-React-App](#-quick-videos-going-over-the-node-install--create-react-app)

    ---

    ## 1. Create a `myproject` folder
    Somewhere inside your Document folder will be good.

    ### Check if you already have Node.js or npm
    React requires **Node ≥ 10.16** & **npm ≥ 5.6**
    Go **inside** the `myproject` folder.

    ```shell
    $ node -v
    $ npm -v
    ```

    ---

    ## 2. Install Node.js
    If Node & npm are missing, let's install them!

    **Options**:
    * [macOS with nodenv](#macos-with-nodenv)
    * [Windows with nvm-windows](#windows-with-nvm-windows)

    ### macOS with [nodenv](https://github.com/nodenv/nodenv)
    We recommend installing Node.js using [nodenv](https://github.com/nodenv/nodenv) to manage node versions. This allows your computer to have a specific Node.js version per project.

    ⚠️ Remove any existing installations of Node.js before installing nodenv! ⚠️
    Having different Node.js installations can lead to conflict issues.

    **Step 1**: Install nodenv with [Homebrew](https://brew.sh/)
    * Update Homebrew:

    ```shell
    brew update && brew upgrade
    ```

    * Install nodenv:

    ```shell
    brew install nodenv
    ```

    **Step 2**: Set up nodenv shell integration
    * Run the initialization command:

    ```shell
    nodenv init
    ```

    * Do as instructed by appending the following line into your shell's rc/profile file:
    ```shell
    eval "$(nodenv init -)"
    ```
    * For Zsh users:
    ```shell
    $ echo 'eval "$(nodenv init -)"' >> ~/.zshrc
    $ cat < ~/.zshrc
    ```
    * For Bash users:
    ```shell
    $ echo 'eval "$(nodenv init -)"' >> ~/.bash_profile
    $ cat < ~/.bash_profile
    ```
    **Step 3**: Implement the changes
    Close & open a new Terminal window for the changes to take place.
    Optional: Verify that nodenv is properly set up using [nodenv-doctor](https://github.com/nodenv/nodenv-installer/blob/master/bin/nodenv-doctor) script.
    * For those using Z shell (Zsh) shell:
    ```shell
    curl -fsSL https://github.com/nodenv/nodenv-installer/raw/master/bin/nodenv-doctor | bash
    ```
    * Expected result:
    ```shell
    Checking for `nodenv' in PATH: /usr/local/bin/nodenv
    Checking for nodenv shims in PATH: OK
    Checking `nodenv install' support: /usr/local/bin/nodenv-install (node-build 3.0.22-4-g49c4cb9)
    Counting installed Node versions: none
    There aren't any Node versions installed under `~/.nodenv/versions'.
    You can install Node versions like so: nodenv install 2.2.4
    Auditing installed plugins: OK
    ```
    **Step 4**: Install Node.js inside the React Workshop folder (`myproject`)
    * Now you're ready to install specific Node.js versions!
    * **Inside** `myproject` folder, install Node.js version `14.5.0`:

    ```shell
    $ cd myproject/
    $ nodenv install 14.5.0
    $ nodenv local 14.5.0
    ```

    Alright! Your Mac is now armed with Node.js!
    Skip down to the [3. Install a Sample React App](#3-install-a-sample-react-app) section!

    ---

    ### Windows with [nvm-windows](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows)
    The following steps are straight from the Microsoft Docs on [Set up NodeJS on native Windows](https://docs.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-windows). We recommend installing and managing Node.js with [nvm-windows](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows)

    ⚠️ Remove any existing installations of Node.js before installing nvm-windows! ⚠️
    Having different Node.js installations can lead to conflict issues.

    **Step 1**: Go to the [windows-nvm's latest release](https://github.com/coreybutler/nvm-windows/releases).
    **Step 2**: Download the **nvm-setup.zip** file for the most recent release.
    **Step 3**: Once downloaded, open the zip file, then open the **nvm-setup.exe** file.
    **Step 4**: The Setup-NVM-for-Windows installation wizard will walk you through the setup steps, including choosing the directory where both nvm-windows and Node.js will be installed.
    * ![install-nvm-for-windows-wizard.png](https://docs.microsoft.com/en-us/windows/images/install-nvm-for-windows-wizard.png)
    **Step 5**: After the installation is complete, open PowerShell & enter `nvm ls`
    * `nvm ls` lists out installed Node versions (should be none at this point)
    * ![windows-nvm-powershell-no-node.png](https://docs.microsoft.com/en-us/windows/images/windows-nvm-powershell-no-node.png)
    **Step 6**: Install Node.js inside the React Workshop folder (`myproject`)
    * Now you're ready to install specific Node.js versions!
    * Inside `myproject` folder, install Node.js version `14.5.0`:

    ```powershell
    $ cd .\Documents\myproject
    $ nvm install 14.5.0
    $ nvm use 14.5.0
    ```

    Alright! Your Windows is now armed with Node.js!
    Skip down to the [3. Install a Sample React App](#3-install-a-sample-react-app) section!

    ---

    ## 3. Install a Sample React App
    Still inside the `myproject` folder, let's install a React App named `frontend`.
    Install:
    * `npx create-react-app frontend`
    Starting it up:
    * Go **inside** the `frontend` folder
    * `npm start`
    ## ⚠️ Got an error?
    * Make sure you are **inside** the `myproject` folder when setting up Node.js
    * Mac: `nodenv local 14.5.0`
    * Windows: `nvm use 14.5.0`
    * Make sure you are **inside** the `frontend` folder when running `npm start`!
    ## ![YouTube](https://user-images.githubusercontent.com/30670749/92354102-a05c4000-f11c-11ea-8964-f96f052b1457.png) Quick Videos Going Over the Node Install & Create-React-App
    <p align="center">
    <a href="https://youtu.be/4Kw-i_rX3tY">
    <img height="200" alt="Installing Node.js & Create a New React App YouTube Thumbnail"
    src="https://img.youtube.com/vi/4Kw-i_rX3tY/mqdefault.jpg">
    </a>
    </p>
    47 changes: 47 additions & 0 deletions A_PromiseError_Demo.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    # Part A: Using Promises in React

    When getting data from an API call, we usually need to use [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises), right?
    So let's try that in our frontend React App.

    ---

    ## Sample Code for App.js
    Here is an example that tries to output an API response in the frontend React App.
    It calls [Random User Generator API](https://randomuser.me/api/), waits for a response, and then creates a React element using the JSON data.
    Let's see what happens!

    File Location: `.../myproject/frontend/src/App.js`

    ```jsx
    import React from 'react';

    // Call Random User Generator API
    const restEndpoint = 'https://randomuser.me/api/';

    // Wait for response & tries to output it to React
    async function App() {
    const response = await fetch(restEndpoint);
    const jsonResponse = await response.json();
    console.log(jsonResponse);

    // React.createElement( type, [properties], [...children]);
    return React.createElement('h1', null, JSON.stringify(jsonResponse));
    };

    export default App;
    ```

    ---

    ## Result - Error

    The `App()` function component returns a promise object immediately as it waits for the Random User Generator API's response.
    React doesn't "wait" for the REST API result, so it tries to create and render the element with the promise object immediately and failing.
    It attempts to display the Random User Generator API response into a React element.
    However, the following error will display instead:

    ```text
    Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
    ```

    ![Promise_Error.png - Kintone_React_Workshop - v2.1](https://user-images.githubusercontent.com/30670749/125893011-dbc39697-4944-4684-84a7-1472aeeb8407.png)
    69 changes: 69 additions & 0 deletions B_Hooks.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    # Part B: Using Hooks in React!

    We will use `useState` & `useEffect` Hooks to handle the REST API calls in React.

    ---

    ## What is `useState` & `useEffect` Hooks

    [useState hooks](https://reactjs.org/docs/hooks-state.html) allow us to use special "state" variables that we can utilize to render into the React UI.

    [useEffect hooks](https://reactjs.org/docs/hooks-effect.html) allow us to run functions after the rendering has finished. We'll use this to run a REST API call and update the state variable, which will then cause React to re-render the UI.

    ## Sample Code for App.js

    File Location: `.../myproject/frontend/src/App.js`

    ```jsx
    // Get started by importing the React JavaScript library & Hooks
    import React, { useState, useEffect } from 'react';

    // Call Random User Generator API
    const restEndpoint = 'https://randomuser.me/api/';

    // Wait for response & tries to output it to React
    // async function App() {
    async function callRestApi() {
    const response = await fetch(restEndpoint);
    const jsonResponse = await response.json();
    console.log(jsonResponse);

    return JSON.stringify(jsonResponse);
    };

    function App() {

    // Establish useState by giving it our initial state
    // const [state, setState] = useState(initialState);

    const [apiResponse, setApiResponse] = useState('*** now loading ***');

    // useEffect takes 2 arguments:
    // 1st = a function, called effect, that is executed when the React Component is rendered
    // 2nd = Array of dependencies to control when effect is to be executed after mounting the component; Empty array = only invoke effect once

    useEffect(() => {
    callRestApi().then(
    result => setApiResponse(result));
    }, []);

    return (
    // JSX includes html-like syntax
    <div>
    <h1>React App</h1>
    <p>{apiResponse}</p>
    </div>
    );
    };

    export default App;
    ```

    ---

    ## Result - Success

    Expected output:
    Outputs the Random User API Call to the frontend React App.

    ![React App with Random User API - Will's Article](https://res.cloudinary.com/practicaldev/image/fetch/s--gLC8WZiw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4hy00cysrqc0a8n2jkf.gif)
    36 changes: 36 additions & 0 deletions C_KintoneDatabase.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    # Kintone Database Solution
    *Built for teamwork, designed by you*

    ## 🚀 Getting your FREE Kintone Database

    ### ① Sign-Up for Developer Program Account (Website) 🌐
    * [bit.ly/KDP_signup](https://bit.ly/KDP_signup)
    * ⚠ Do NOT use Safari
    * ⚡Accept Cookies First
    * ✅ Use Chrome & Firefox

    ### ② THEN Create a Kintone Subdomain (Database) 📂
    * [bit.ly/K_DevLic](http://bit.ly/K_DevLic)
    * ⚡ Only use lowercase, numbers, & hyphens in your subdomain
    * ⚠ Do not use uppercase nor special characters

    Confused? 🤔 → Check out the video below:

    ### 📺 Sign up for Kintone Developer Program & Developer License

    [![https://youtu.be/Gzz8SbTuoFg](https://img.youtube.com/vi/Gzz8SbTuoFg/mq1.jpg)](https://youtu.be/Gzz8SbTuoFg)
    <https://youtu.be/Gzz8SbTuoFg>

    ## Create a Kintone App

    Let's create a Kintone App to list off your favorite [Manga](https://en.wikipedia.org/wiki/Manga)s!

    Here are the **required** fields & their **configurations** for our workshop:

    | Field Type | Field Name | Field Code | Note |
    | ------------- | ------------- | ---------- | --------------------------------- |
    | Text | Title | `title` | The manga's title |
    | Text | Author | `author` | The manga's author |
    | Record number | Record number | `recordID` | Auto generated IDs for each entry |

    ![Create_App_Demo.gif Kintone_React_Workshop v2.1](https://user-images.githubusercontent.com/30670749/125898739-1bc018ac-1740-40e0-91cc-ab829192d2ea.gif)
    62 changes: 62 additions & 0 deletions D_CORS_Error_Demo.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,62 @@
    # Part D: CORS Error Demo

    Now that we are outputting Random User Generator API's response onto our frontend React App let's output more useful results!
    Using Kintone's low-code Database platform, we can easily create & host a database that is accessible with REST APIs.

    But can we just swap the request endpoint with Kintone's?

    ---

    ## Sample Code for App.js
    We will try a GET request to Kintone from our frontend React App.

    If you want to run this code, be sure to input your Kintone specifications for `subdomain`, `appID`, and `apiToken`.

    File Location: `.../myproject/frontend/src/App.js`

    ```jsx
    import React, { useState, useEffect } from 'react';

    // Kintone API Setup
    const subdomain = ''; //Enter your Kintone Subdomain (ex: devevents)
    const appID = ''; //Enter your App's ID number (ex: 1)
    const apiToken = ''; //Enter your App's API Token

    const getKintoneData = async () => {
    const requestEndpoint = `https://${subdomain}.kintone.com/k/v1/records.json?app=${appID}`;
    const fetchOptions = {
    method: 'GET',
    headers: { 'X-Cybozu-API-Token': apiToken }
    };
    const response = await fetch(requestEndpoint, fetchOptions);
    const jsonResponse = await response.json();
    console.log(jsonResponse);
    return JSON.stringify(jsonResponse);
    };

    function App() {
    const [apiResponse, setApiResponse] = useState('*** now loading ***');

    useEffect(() => {
    getKintoneData().then(
    result => setApiResponse(result));
    }, []);

    return (
    <div>
    <h1>React App</h1>
    <p>{apiResponse}</p>
    </div>
    );
    };

    export default App;
    ```

    ---

    ## Result - CORS Error

    [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) Error occurs since we cannot access the resources that lie on Kintone's domain directly from our domain (frontend React App).

    ![CORS_Error_Crop.png Kintone_React_Workshop v2.1](https://user-images.githubusercontent.com/30670749/125892916-ef0f189c-af9f-4dc4-95d6-c0a111bb7238.png)
    83 changes: 83 additions & 0 deletions E_ExpressServer.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,83 @@
    # Installing the Express Server (backend)

    **Outline**
    * [What is Express?](#what-is-express)
    * [Installing the Express Server](#installing-the-express-server)
    * [Starting the Express Server](#starting-the-express-server)
    * [Debugging](#debugging)

    ## What is Express?
    [Express](https://expressjs.com/) is a backend web application framework for Node.

    We will use Express to create custom endpoints that our frontend React App can make calls to. When we make requests to these custom endpoints, the Express server will make REST API calls to our desired 3rd party service endpoint, receive the response, and then route the response back to our frontend React App.

    ## Installing the Express Server
    (1) From your terminal, go to your **myproject** folder

    ```bash
    cd .../myproject
    ```

    (2) Create **backend** folder

    ```bash
    mkdir backend

    cd backend
    ```

    (3) Create your Express project

    ```bash
    npm init
    ```

    * Hit enter to skip the questions

    (4) Continue to install some dependencies

    ```bash
    npm install express node-fetch cors
    ```


    (5) Create a **server.js** file inside the **backend** folder

    ```bash
    touch server.js
    ```

    ## Starting the Express Server
    (1) Configure the **server.js** file

    (2) From your terminal, go to your **backend** folder

    ```bash
    cd .../myproject/backend
    ```

    (3) Start the Express Server

    ```bash
    node server.js
    ```

    ---

    ## Debugging

    No response when starting the Express server?
    * Make sure you are inside the `backend` folder when starting the Express server

    Got a `UnhandledPromiseRejectionWarning` error?

    ```text
    (node:5379) UnhandledPromiseRejectionWarning: FetchError: request to https://.kintone.com/k/v1/records.json?app= failed, reason: getaddrinfo ENOTFOUND .kintone.com
    ```

    * Looks like Kintone API credentials are missing
    * Be sure to enter your Subdomain, App ID, and API Token under the `Kintone API Setup` section in `server.js`

    Got a `GAIA_IA02` error?
    * Enter the App's API Token in `apiToken`
    * Be sure to hit the `save` button & the `Update App` button to implement the API Token change.
    156 changes: 156 additions & 0 deletions F_GET_Data.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,156 @@
    # Part F: GET data from the Kintone App

    Let's grab data from the Kintone Database App and output it to our frontend React App!

    To implement the GET request, we will be creating the following files:
    * [backend - server.js](#backend---serverjs)
    * [frontend](#frontend)
    * [getList.js](#getlistjs)
    * [App.js](#appjs)

    ---

    ## backend - server.js
    We will set up an Express server that calls Kintone on behalf of the frontend React App to avoid the CORS error.

    Expected result:
    * Calls Kintone's GET Records API when <http://localhost:5000/getData> endpoint is requested with a GET request
    * Returns the JSON response to frontend React App (<http://localhost:3000>)

    File Location: `.../myproject/backend`

    ```js
    // backend - server.js

    // Express Server Setup
    const express = require('express');
    const cors = require('cors');
    const fetch = require('node-fetch');

    const PORT = 5000;
    const app = express();

    // Parse incoming requests with JSON payloads
    app.use(express.json());

    // Set Cross-Origin Resource Sharing (CORS) to frontend React App
    app.use(cors());
    const corsOptions = {
    origin: 'http://localhost:3000'
    };

    // Kintone API Setup
    const subdomain = ''; //Enter your Kintone Subdomain (ex: devevents)
    const appID = ''; //Enter your App's ID number (ex: 1)
    const apiToken = ''; //Enter your App's API Token (ex: cJrAD9...)

    // Append a Query Parameters to the Request Endpoint
    const parameters = 'query=order by recordID asc';

    // Call Kintone's GET Records API
    const multipleRecordsEndpoint = `https://${subdomain}.kintone.com/k/v1/records.json?app=${appID}&${parameters}`

    // This runs if a GET request calls for localhost:5000/getData
    app.get('/getData', cors(corsOptions), async (req, res) => {
    const fetchOptions = {
    method: 'GET',
    headers: {
    'X-Cybozu-API-Token': apiToken
    }
    }
    const response = await fetch(multipleRecordsEndpoint, fetchOptions);
    const jsonResponse = await response.json();
    res.json(jsonResponse);
    });

    app.listen(PORT, () => {
    console.log(`Example app listening at http://localhost:${PORT}`);
    });
    ```

    ---

    ## frontend
    Now that we got our Express server setup, time for configuring the frontend React App!

    Expected Result:
    Data from the Kintone App will be outputted as bullet points at <http://localhost:3000/>.

    ### getList.js
    First, we will create a `requests` folder inside the `frontend/src/`.
    This is where we will add the two functions that interacts with React and Kintone.

    In `getList.js`, we will create a list array by looping through Kintone's response.

    **Kintone API Notes**:
    * `record.title.value` is the value of the Title field
    * `record.author.value` is the value of the Author field

    **React Note**:
    * When creating a list in React, assign an unique ID to each item
    * We will use `record.recordID.value` for the keys

    File Location: `.../myproject/frontend/src/requests/getList.js`

    ```jsx
    // getList.js - Create a list array

    // Declare the GET endpoint defined in our Express server
    const getRecordsEndpoint = "http://localhost:5000/getData";

    export default async function getList() {
    const response = await fetch(getRecordsEndpoint);
    const jsonResponse = await response.json();

    console.log(jsonResponse);

    const arrayOfLists = jsonResponse.records.map(
    record =>
    <li key={record.recordID.value}><b>{record.title.value}</b> written by {record.author.value}</li>
    )

    return arrayOfLists;
    };
    ```

    ### App.js
    We will be importing the `getList` module for the Kintone records-based list items.

    File Location: `.../myproject/frontend/src/App.js`

    ```jsx
    // App.js - Parent Component

    import React, { useState, useEffect } from 'react';

    import getList from './requests/getList.js'; // Used to get Kintone data

    function App() {
    const [listItems, setListItems] = useState('*** now loading ***');
    useEffect(() => {
    getList().then(
    result => setListItems(result)
    );
    }, []);

    return (
    <div>
    <div>
    <h1>React Manga List App</h1>
    <ul>{listItems}</ul>
    </div>
    </div>
    );
    }

    export default App;
    ```

    ---

    ## Result - Kintone Database App's data displayed as bullet points

    Here is what it looks like when displaying our Manga DB App.
    It lists out our favorite Japanese comics, ordered by `recordID`.

    ![Will's Article - React App with Clean Kintone Data](https://res.cloudinary.com/practicaldev/image/fetch/s--mL-QZl81--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qj4lm74w34y3kct44px.png)
    258 changes: 258 additions & 0 deletions G_POST_Data.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,258 @@
    # Part G: POST data to the Kintone App

    Now that we can retrieve & display the data from the Kintone Database App let's submit new data via our frontend React App!
    We will do this by adding a POST request route on the Express server used when the user inputs via the form on the frontend React App.

    To implement the POST request, we will be creating the following files:
    * [backend - server.js](#backend---serverjs)
    * [frontend](#frontend)
    * [getList.js](#getlistjs)
    * [postRecord.js](#postrecordjs)
    * [InputForm.js](#inputformjs)
    * [App.js](#appjs)

    **Note**
    Be sure to restart your Express server when updating `server.js`.
    * `Control` + `C` to end the Express server
    * `node server.js` to start it up again

    ## backend - server.js
    We will add another endpoint to make our POST requests.

    Expected result:
    * When `localhost:5000/getData` endpoint is called, a GET request is sent to Kintone for data retrieval.
    * When `localhost:5000/postData` endpoint is called, a POST request is sent to Kintone to update the database with the submitted entry.

    File Location: `.../myproject/backend`

    ```js
    // backend - server.js

    // Express Server Setup
    const express = require('express');
    const cors = require('cors');
    const fetch = require('node-fetch');

    const PORT = 5000;
    const app = express();

    // Parse incoming requests with JSON payloads
    app.use(express.json());

    // Set Cross-Origin Resource Sharing (CORS) to frontend React App
    app.use(cors());
    const corsOptions = {
    origin: 'http://localhost:3000'
    };

    // Kintone API Setup
    const subdomain = ''; //Enter your Kintone Subdomain (ex: devevents)
    const appID = ''; //Enter your App's ID number (ex: 1)
    const apiToken = ''; //Enter your App's API Token (ex: cJrAD9...)

    // Append a Query Parameters to the Request Endpoint
    const parameters = 'query=order by recordID asc';

    // Call Kintone's GET Records API
    const multipleRecordsEndpoint = `https://${subdomain}.kintone.com/k/v1/records.json?app=${appID}&${parameters}`

    // Call Kintone's GET Record API
    const singleRecordEndpoint = `https://${subdomain}.kintone.com/k/v1/record.json?app=${appID}&${parameters}`;

    // This runs if a GET request calls for localhost:5000/getData
    app.get('/getData', cors(corsOptions), async (req, res) => {
    const fetchOptions = {
    method: 'GET',
    headers: {
    'X-Cybozu-API-Token': apiToken
    }
    }
    const response = await fetch(multipleRecordsEndpoint, fetchOptions);
    const jsonResponse = await response.json();
    res.json(jsonResponse);
    });

    // Add a New Route for a POST request using singleRecordEndpoint

    // This runs if a POST request calls for localhost:5000/postData
    app.post('/postData', cors(corsOptions), async (req, res) => {
    const requestBody = {
    'app': appID,
    'record': {
    'title': {
    'value': req.body.title
    },
    'author': {
    'value': req.body.author
    }
    }
    };
    const options = {
    method: 'POST',
    headers: {
    'X-Cybozu-API-Token': apiToken,
    'Content-Type': 'application/json',
    },
    body: JSON.stringify(requestBody)
    }
    const response = await fetch(singleRecordEndpoint, options);
    const jsonResponse = await response.json();
    res.json(jsonResponse);
    });

    app.listen(PORT, () => {
    console.log(`Example app listening at http://localhost:${PORT}`);
    });
    ```

    ## frontend
    We will add a form for user input and function to make a POST request on our newly defined Express server's endpoint.

    Expected result:
    * Display Kintone app data as a clean list
    * Form at the bottom to add user input
    * When an input is submitted, a POST request is sent out & the list is updated

    ### getList.js

    `getList.js` will be the same as shown in [Part F](https://gist.github.com/ahandsel/813e642bf36008192708c50a23185935#file-f_get_data-md).

    File Location: `.../myproject/frontend/src/requests/getList.js`

    ### postRecord.js
    Similar to `getList.js`, we will add `postRecord.js` in the `requests` folder to handel the Kintone POST API calls.

    ```jsx
    // postRecord.js - Post to Kintone

    // Declare the GET & POST endpoints defined in our Express server
    const addRecordEndpoint = "http://localhost:5000/postData";

    // Make REST API Calls & take in the values stored in the state variables related to the input fields
    export default async function postRecord(title, author) {
    const recordBodyParameters = {
    'title': title,
    author // ES6 syntax that functions the same as above
    }

    const options = {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json'
    },
    body: JSON.stringify(recordBodyParameters)
    }

    const response = await fetch(addRecordEndpoint, options);
    const jsonResponse = await response.json();

    console.log(JSON.stringify(jsonResponse));

    return jsonResponse;
    };
    ```

    ### InputForm.js
    We will now create a React component that appends a form on our React App.

    Create a `components` folder in the `src` folder. This is where we will create `InputForm.js`.

    We will import two files in the `requests` folder to make GET & POST API calls to Kintone.

    We will create and export the form component.

    File Location: `.../myproject/frontend/src/components/InputForm.js`

    ```jsx
    // InputForm.js - Create a form that makes a POST request

    import { useState } from 'react';
    import getList from '../requests/getList.js';
    import postRecord from '../requests/postRecord.js';

    function InputForm(props) {
    const [title, setTitle] = useState("");
    const [author, setAuthor] = useState("");

    function buttonClick(title, author) {
    postRecord(title, author)
    .then(() => getList()) // Trigger re-rendering the getList
    .then(result => props.setListItems(result))
    }

    function handleTitleChange(event) {
    setTitle(event.target.value);
    }
    function handleAuthorChange(event) {
    setAuthor(event.target.value);
    }

    return (
    <div>
    <form>
    <div>
    <label>Title: </label>
    <input
    type="text"
    value={title}
    onChange={andleTitleChange}
    />
    </div>
    <div>
    <label>Author: </label>
    <input
    type="text"
    value={author}
    onChange={handleAuthorChange}
    />
    </div>
    <button type="button" onClick={() => buttonClick(title, author)}>Post to Kintone</button>
    </form>
    </div>
    );
    };
    export default InputForm;
    ```

    ### App.js
    For the form component, we will import `InputForm`.
    We will add the InputForm in the div we are exporting.

    For the GET API call function, we will import `getList`.

    File Location: `.../myproject/frontend/src/App.js`

    ```jsx
    // App.js - Parent Component

    import React, { useState, useEffect } from 'react';
    import getList from './requests/getList.js';

    // Get the form component
    import InputForm from './components/InputForm.js'

    function App() {
    const [listItems, setListItems] = useState('*** now loading ***');
    useEffect(() => {
    getList().then(
    result => setListItems(result)
    );
    }, []);

    return (
    <div>
    <div>
    <h1>React Manga List App</h1>
    <ul>{listItems}</ul>
    </div>
    <InputForm setListItems={setListItems} />
    </div>
    );
    }

    export default App;
    ```

    ## Result - Kintone Database App's data displayed as bullet points with a form to submit a new entry

    ![Will's Article - React App with Data & Form](https://res.cloudinary.com/practicaldev/image/fetch/s--IwgycySX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a8ls55md2dhqm82ksspe.png)
    50 changes: 50 additions & 0 deletions X_Troubleshooting.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,50 @@
    # Troubleshooting Notes

    ## Starting the frontend React Project
    Enter the following commands in your terminal
    * $ `cd ../myproject/frontend`
    * $ `npm start`

    Then access your React project at
    * `http://localhost:3000/`

    ## Starting the backend Express Server
    Enter the following commands in your terminal
    * $ `cd ../myproject/backend`
    * $ `node server.js`

    Then access your Express server at
    * `http://localhost:5000/`

    Access the Kintone API call at
    * `http://localhost:5000/getData`

    ## Kintone Section: React not updating after updating server.js
    Be sure to restart the server after making changes to server.js!

    (1) Go to the terminal running the Express server.
    It should look something like this:

    ```shell
    user@computer backend % node server.js
    Example app listening at http://localhost:${PORT}
    ```

    (2) Restart the Express server
    * Stop the server: `ctrl + c`
    * Start the server: $ `node server.js`

    (3) Reload the browser showing the React App.
    * `http://localhost:3000/`

    ## Kintone API Token

    To generate an API Token for a Kintone App:
    1. Go to the Kintone App
    2. Go to the Gear icon ⚙️ (top right corner) > Open the App Settings page
    3. Click on the **App Settings** Tab > Click on **API Token** settings
    4. Click the `Generate` button to generate a token
    5. Click the `Save` button (top left corner) to save the token setting
    6. Finally, click the `Update App` button (top right corner) to implement the token setting change.

    ![Generating an API Token Gif](https://user-images.githubusercontent.com/30670749/111570449-3964c580-87e8-11eb-83ee-9a6a1ff2e8df.gif)
    21 changes: 21 additions & 0 deletions Y_Survey.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,21 @@
    # Thank you for attending our workshop!

    ## Your Feedback Please 🙇
    Please fill out this quick survey for a chance to win 💰️ $25 Amazon Gift Card:

    <!-- BeMyApp's -->
    ## [bit.ly/KDP_Q](http://bit.ly/KDP_Q)

    ## Next Step
    For those wanting a visualization projects:
    * Try linking to different [amChart libraries](https://www.amcharts.com/demos/), and reuse the code we used in the workshop!

    For those wanting to create projects on Kintone and want to retrieve & store data from public APIs:
    * Call [public APIs](https://github.com/public-apis/public-apis#index) from Kintone!

    For those wanting to use Kintone as a back-end database:
    * Check out [Deploy a REST API calling node.js App to Heroku](https://dev.to/will_yama/deploy-a-rest-api-calling-node-js-app-to-heroku-2mia) tutorial!

    ## Where to Get Help?
    * [Kintone Developer Community forum](https://developer.kintone.io/hc/en-us/community/posts)
    * [Stack Overflow](https://stackoverflow.com/)
  4. @ahandsel ahandsel created this gist Aug 19, 2021.
    1 change: 1 addition & 0 deletions 00_React_Workshop_v3_Test.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    _