GraphQL and React




CS174

Chris Pollett

Nov 30, 2022

Outline

Website Architecture Revisited - MVVM

Model view view-model architecture

A Simple View Model with GraphQL

Running our GraphQL App

More on Schemas and Resolvers

A Second GraphQL app

import { ApolloServer, gql } from 'apollo-server-express';
import express from 'express';
const port = process.env.PORT || 8888;
let notes = [
    {id: '1', content: 'First note', author: 'bob'},
    {id: '2', content: 'Another note', author: 'sally'},
    {id: '3', content: 'super note', author: 'alice'},
];
const typeDefs = gql`
    type Note {
        id: ID!
        content: String!
        author: String!
    }

    type Query {
        hello: String
        notes: [Note!]!
        note(id: ID): Note!
    }

    type Mutation {
        newNote(content: String!): Note!
    }
`;
const resolvers = {
    Query : { // these are the handlers for queries
        hello: () => 'Hello there!',
        notes: () => notes,
        note: (parent, args) => {
            return notes.find(note => note.id === args.id)
        }
    },
    Mutation: {
        newNote: (parent, args) => {
            let noteValue = {
                id: String(notes.length + 1),
                content: args.content,
                author: "Chris Pollett"
            };
            notes.push(noteValue);
            return noteValue;
        }
    }
};
const app = express();
const server = new ApolloServer({typeDefs, resolvers});
await server.start()
server.applyMiddleware( {app, path: '/api'} );
app.listen( {port }, () =>
    console.log(`GraphQL Example on ${port}${server.graphqlPath}`));

Second GraphQL app in Playground, Security, Concluding Remarks

GraphQL Querying Notes
GraphQL Adding a Note

In-Class Exercise

Client Side Javascript Frameworks

Creating a Simple React App

A Brief Exploration of Default Files

Connect React with GraphQL and Apollo

Routing and New Tags

import { BrowserRouter, Link, Route, Routes, useParams,}
    from 'react-router-dom';
import React from 'react';

/* This page has multiple components on it we could
   have split this across multiple files and imported them.
 */

/* This component shows react components can have forms.
   It also shows a crude way to get the values off forms.
   You could then send these values as a GraphQL query
 */
class Home extends React.Component
{
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleSubmit(event) {
        let user_name = document.getElementById('user-name').value;
        alert(user_name);
        event.preventDefault();
    }
    render() {
        return (
            <div className="app">
              {/* We can enclosed a C comment in braces to make a JSX comment
                */}
              <h1>Home Page Body</h1>
              <form  onSubmit={this.handleSubmit}>
              <p><label for="user-name">User Name:</label>
              <input id="user-name" type="text"/>
              <button type="submit">Submit</button>
              </p>
              </form>
            </div>
          );
    }
};

/* Here is a functional way to declare a component...
    Notice a previously defined component can be used as
    a tag in another component. This allows one to
    have code that looks more like HTML rather than
    have to call functions from your scripting language which
    render elements.
 */
const AnotherHome  = () => {
    return (
        <div className="app">
          <h1>About Page</h1>
          <p>Demoing we can use tags we have just defined...</p>
          <Home />
        </div>
      );
};

/* We are going to use the number component below to
   show how to bind url path variables to Javascript variables
 */
const Number = () => {
    const { my_number1, my_number2 } = useParams();
    return (
        <div className="app">
          <h1>MyNumber {my_number1} {my_number2}</h1>
        </div>
      );
};

// We'll render this component on failure to find a Route
const NotFound  = () => {
    return (
        <div className="app">
          <h1>Page not found</h1>
        </div>
      );
};

const App = () => (
  <BrowserRouter>
    <div>
      {/*Notice how make links in React for routing */}
      <Link to="/">Home</Link>{' '}
      <Link to='/number/5/6'>Number-5-6</Link>{' '}
      <Link to='/another_home'>Another Home</Link>{' '}

      {/*React renders first route which matches */}
      <Routes>
        <Route exact path="/" element={<Home />} />
        <Route path="/another_home" element={<AnotherHome />} />

        {/*notice this route matches paths like /number/1/4 */}
        <Route path="/number/:my_number1/:my_number2" element={<Number />} />

        {/*notice the wildcard in this route */}
        <Route path="/*" element={<NotFound />} />
      </Routes>
    </div>
  </BrowserRouter>
);
export default App;