본문 바로가기

토이 프로젝트

GraphQL, Sequelize, MySql, React (apollo server, apollo client) - CRUD 구현

우선 내가 생각하는 GraphQL의 장점은

 

1. rest api로 작성할때 각 url 마다 api 를 만들어줄 필요없이 하나의 end-point로 데이터를 주고받는 것이 가능하는 것이다.

 

2. 내가 만들어 놓은 query나 mutation을 이용하여 필요한 값들만 정확하게 가져와 데이터 낭비를 줄일 수 있다.

 

더 많은 장점들이 있지만 우선 생각나는 것들이 이것들 뿐이다. 그리고 단점은 file전송 같은 것을 할 때 복잡하다.

 


이 포스팅을 하는 이유는 주로 Sequelize와 MySQL을 같이 쓰는데 이렇게 GraphQL, Sequelize, MySQL 세 가지를 같이 활용해서 만든 예제들이 충분하지 않아, 만들기 어려웠기 때문이다. 그리고 서버는 아폴로 서버를 이용하여 만들 것이고 프론트는 리액트에 아폴로 클라이언트를 이용하여 데이터를 프론트엔드로 받아올 것이다.

 

토이프로젝트의 목적은 단계적으로 크게 세 가지다.

 

1. sequelize를 이용하여 server와 mysql을 연결시킨다.

 

2. db와 연결된 server를 GraphQL을 이용하여 데이터를 뽑아온다.

 

3. 뽑아온 데이터를 client(front-end)에서 그려낸다.

 


1. 필요한 package들을 다운로드한다.

npm init -y
npm install --save apollo-server express express-graphql graphql mysql mysql2 nodemon sequelize

 

2. 프로젝트 폴더 안에서 sequelize init을 이용하여 sequelize 환경을 세팅한다.

sequelize init

 

3. config/config.json에 자신의 db 정보를 입력해준다.

{
  "development": {
    "username": "root",
    "password": "****",
    "database": "test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}

 

4. models/index.js에 아래 코드를 입력한다.

'use strict';

const path = require('path');
const Sequelize = require('sequelize');
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};

const sequelize = new Sequelize(
  config.database,
  config.username,
  config.password,
  config
);


db.sequelize = sequelize;
db.Sequelize = Sequelize;

db.User = require("./user")(sequelize, Sequelize);

module.exports = db;

 

5. models/user.js를 만들어 생성할 table 정보를 정의한다.

module.exports = (sequelize, DataTypes) =>
sequelize.define(
  "user",
  {
    firstName: {
      type: DataTypes.STRING(40),
      allowNull: true,
    },
    lastName: {
      type: DataTypes.STRING(40),
      allowNull: true,
    },
    password: {
      type: DataTypes.STRING(100),
      allowNull: true,
    },
  },
  {
    timestamps: true,
    paranoid: true,
  }
);

 

6. 제일 하위 경로에 서버가될 index.js를 만든다.

const express = require('express');
const app = express();
const PORT = 3030;
const path = '/graphql';
const { ApolloServer, gql } = require('apollo-server-express');
const { User } = require('./models/index');

User.sequelize.sync().then(() => {
  console.log("sequelize success")
}).catch(err => {
  console.log("sequelize fail", err)
})

const typeDefs = gql`

  type User {
    id: Int
    firstName: String
    lastName: String
    password: String
  }

  type Query {
    getUserData: [User!]!
    getAllUser(id: Int!): User
  }

  type Mutation {
    createUser(firstName: String!, lastName: String!, password: String!): User
    updateUser(id: Int!, firstName: String!, lastName: String!, password: String!): User
    deleteUser(id: Int!, firstName: String!, lastName: String!, password: String!): User
  }
`;

const resolvers = {
  Query:  {
    getUserData: async () => {
      const getUsers = await User.findAll();
      return getUsers;
    },
    getAllUser: async (_, args) => {
      await context.User.findOne()
      console.log(args)
      const { id } = args;
      const resultData = await User.findOne( {where: { id: id } });
      return resultData;
    }
  },
  Mutation: {
    createUser: async (_, { firstName, lastName, password }) => {
      const newUser = await User.create({ 
        firstName,
        lastName,
        password
      });
      
      const user = await User.findOne( { where: { id: id } });
      return user;
    },
    updateUser: async (_, { id, firstName, lastName, password }) => {
      console.log(id)
      const oldUser = await User.update({firstName, lastName, password}, {where: { id: id } });
      const user = await User.findOne( { where: { id: id } });
      return user;
    },
    deleteUser: async (_, { id }) => {
      console.log(id)
      const oldUser = await User.destroy({where: { id: id } });
      const user = await User.findOne( { where: { id: id } });
      return user;
    },
  }
};

const server = new ApolloServer({ typeDefs, resolvers });
server.applyMiddleware({ app, path });

// The `listen` method launches a web server.
app.listen({ port: PORT }, () =>
  console.log(`🚀 Server ready at http://localhost:${PORT}${path}`)
)

typeDefs는 쿼리를 보낼 것의 형태를 정의해준다.

resolvers에는 query나 mutation에서 쓸 sequelize문들을 정의해 준다.

그리고 ApolloServer에서 이것들을 이용하여 playground를 만들어준다.

 

이렇게 되면 큰 틀에서 server의 준비는 끝났다. crud기능들의 쿼리들은 모두 만들었다.

 

GraphQL에서는 query에서는 read기능만을 넣어야하고 mutation에는 create, update, delete기능을 넣어야한다.

 


이제 client(front-end) 환경 설정을 해야한다.

 

1. front가 될 폴더에서 react환경을 다운받아준다.

npm init -y
npx create-react-app ./
npm install --save graphql @apollo/client react-router-dom styled-components

 

2.  만들어진 react 환경에서 index.js에 들어간다.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';


import { ApolloClient, InMemoryCache, useQuery } from '@apollo/client';
import { ApolloProvider, gql } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:3030/graphql',
  cache: new InMemoryCache()
});

ReactDOM.render(
  <React.StrictMode>
    <ApolloProvider client={client}>
    <App />
    </ApolloProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();

 

3. App.js에 들어간다.

import React, { useState, useEffect } from "react";
import './App.css';

import { ApolloClient, InMemoryCache, useQuery } from '@apollo/client';
import { ApolloProvider, gql } from '@apollo/client';




  function App() {
    const GET_USER = gql`
      query{
        getUserData{
          firstName
          lastName
          password
        }
      }
      `
      
    const { loading, error, data } = useQuery(GET_USER);
    
    if (loading) return <p>'Loading...'</p>
    if (error) return `Error ${error.message}`
    
    return (
      <div>
        <h1>{data.getUserData.map((value, key)=> (<div>{value.firstName}</div>))}</h1>
        <h2>My first Apollo app 🚀</h2>
      </div>
  );
}

export default App;

지금은 간단하게 userdata를 가져오는 쿼리만 날려보았다. 이런식으로 응용하여 만들어놓은 crud 기능들을 다 활용할 수 가 있다.

 

 

자세한 코드는 github에 올려놓았다.

 

github.com/ukcasso/graphql_sequelize_mysql

 

ukcasso/graphql_sequelize_mysql

Contribute to ukcasso/graphql_sequelize_mysql development by creating an account on GitHub.

github.com

 

그리고 자세한 것들은 역시나 공식문서들을 참고해 보는 것이 좋다.

www.apollographql.com/docs/apollo-server/

 

Introduction to Apollo Server

A guide to using Apollo Server

www.apollographql.com

 

www.apollographql.com/docs/react/

 

Introduction to Apollo Client

A guide to using the Apollo GraphQL Client with React

www.apollographql.com

sequelize.org/

 

Sequelize

 

sequelize.org