Skip to content

Instantly share code, notes, and snippets.

@wulymammoth
Last active July 17, 2021 18:21
Show Gist options
  • Save wulymammoth/5ffbb07d9faa04b9a2018508879b6bfd to your computer and use it in GitHub Desktop.
Save wulymammoth/5ffbb07d9faa04b9a2018508879b6bfd to your computer and use it in GitHub Desktop.

Girls in Tech // Putting It Together: NodeJS, API hook up & React

Who am I?

David Wu

  • contact

    • twitter: @wulymammoth
    • github: github.com/wulymammoth
  • work

    • currently: senior software engineer on infrastructure, EasyPost
    • previously: full-stack engineer, The RealReal
  • background

    • primarily self-taught
    • undergraduate studies at the University of California, Berkeley
      • ISF (interdisciplinary studies field)
        • computer science
        • cognitive science
        • statistics
        • sociology
        • psychology

What are we doing today

Learn about how most web-applications and services that we use from AirBnb, to Instagram, to how your packages get to your doorstep are built today

You may have heard a lot about ReactJS or even have dabbled in it. You also may have heard about NodeJS or have even dabbled in it. I want to give you a good mental model on how all the pieces fit together and play together to hopefully give you all a starting point or foundation in which to start exploring more should this be of immense interest to you.

I'll start by discussing what things look like in a web service or application from a high level and some of the pieces involved, including some of the nomenclature common in this domain, and then we'll dive into some code. I'll be focusing more on the "backend" or API/server-side with NodeJS today, and if we have time, we'll talk about how to get what we have up onto the web and/or build on it.

Please, feel free to stop me at any time to ask questions.


Lay of the land

Overview (Whimsical)

  • understanding client vs server
    • why we need servers
    • requests and responses

Building

pre-requisites

set-up

simple counter

var React = require("react");

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  decrement() {
    this.setState({ count: this.state.count - 1 });
  }

  increment() {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <span onClick={() => this.decrement()}>-</span>
        <span>{this.state.count}</span>
        <span onClick={() => this.increment()}>+</span>
      </div>
    );
  }
}

shopping list

import "./App.css";

var React = require("react");

async function postData(url = "", data = {}) {
  // Default options are marked with *
  const response = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });
  return response.json(); // parses JSON response into native JavaScript objects
}

class ListItem extends React.Component {
  constructor(props) {
    super(props);
    this.state = { idx: props.key, name: props.name, purchased: false };
  }

  toggleCheck() {
    const newState = Object.assign(this.state, { purchased: !this.state.purchased });
    this.setState(newState);
    postData("/items", { foo: "bar" }).then((data) => {
      console.log(data);
    });
  }

  render() {
    return (
      <li>
        <input type="checkbox" defaultChecked={this.state.purchased} onChange={() => this.toggleCheck()} />
        <label>{this.state.name}</label>
      </li>
    );
  }
}

class ShoppingList extends React.Component {
  constructor(props) {
    super(props);
    this.state = { items: [] };
  }

  componentDidMount() {
    fetch("/items")
      .then((response) => response.json())
      .then((data) => {
        this.setState({ items: data.items });
      });
  }

  render() {
    const items = this.state.items;
    return (
      <ul>
        {items.map((item, idx) => (
          <ListItem key={idx} name={item} />
        ))}
      </ul>
    );
  }
}

class EntryField extends React.Component {
  constructor(props) {
    super(props);
    this.state = { entry: "" };
  }

  handleInput = (event) => {
    this.setState({ entry: event.target.value }, () => {
      console.log(`'entry' state: ${this.state.entry}`);
    });
  };

  handleSubmit = (event) => {
    postData("/items", { item: this.state.entry }).then((data) => {
      console.log(data);
    });
  };

  render() {
    return (
      <div>
        <input onChange={this.handleInput} type="text" id="entry" name="entry" placeholder="add new entry" />
        <button onClick={this.handleSubmit}>submit</button>
      </div>
    );
  }
}

function App() {
  return (
    <div className="App">
      <Counter />
      <br />
      <ShoppingList />
      <br />
      <EntryField />
    </div>
  );
}

export default App;
// EXPRESS (API)
var express = require("express");
var router = express.Router();

let counter = 0;
let items = [];

/* GET home page. */
router.get("/", function (req, res, next) {
  res.render("index", { title: "foobar" });
});

router.get("/foobar", function (_req, res, _next) {
  res.send("foobar baz\n");
});

router.get("/items", function (_req, res, _next) {
  res.send({ items: items });
});

router.post("/items", function (req, res, _next) {
  const newItem = req.body.item;
  items.push(newItem);
  console.log(++counter);
  res.send({ items: items });
  //res.status(200).end();
});

module.exports = router;
  • using the browser's "fetch" API
    • GET: for fetching data
    • POST: for creating and persisting data
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment