GraphQL & Apollo

니나노개발생활·2022년 4월 2일
1

💡ah-ha

목록 보기
51/51
post-thumbnail

GraphQL

REST API의 한계

  • overfetching
    API를 통해 받아온 데이터들 중 특정 필요한 정보들만 필요하지만 모든 정보를 다 받아와야함.
  • underfetching
    하나의 API에 필요한 정보가 없을 경우, 이를 한번에 받아오기 위해 요청을 2개를 받아와야함.

☝🏻 GraphQL은 최소한의 요청으로 내가 원하는 정보만 받아 데이터의 낭비와 API 횟수를 줄일 수 있다.

GraphQL로 데이터 주고받기

요청(query)

  1. REST API GET과 동일하게 모든 데이터를 요청
query {
  teams {
    id
    manager
    office
    extension_number
    mascot
    cleaning_duty
    project
  }
}
  1. 팀의 필요한 데이터만 요청(REST API의 overfetching 해결)
query {
  teams {
    manager
    office
  }
}

query {
  team(id: 1) {
    manager
    office
  }
}
  1. 팀 정보과 해당 팀 멤버들의 정보를 2번의 요청이 아닌 한번에 요청(REST API의 underfetching 해결)
query {
  team(id: 1) {
    manager
    office
    members {
      first_name
      last_name
    }
  }
}

query {
  teams {
    manager
    office
    mascot
  }
  roles {
    id
    requirement
  }
}

추가, 수정, 삭제(mutation)

mutation {
  // 추가 : postTeam
  // 수정 : editTeam
  // 삭제 : deleteTeam
  postTeam (input: {
    manager: "John Smith"
    office: "104B"
    extension_number: "#9982"
    mascot: "Dragon"
    cleaning_duty: "Monday"
    project: "Lordaeron"
  }) {
    manager
    office
    extension_number
    mascot
    cleaning_duty
    project
  }
}

GraphQL의 장점

  • 필요한 정보들만 선택하여 받아올 수 있음
    overfetching 문제 해결, 데이터 전송량 감소
  • 여러 계층의 정보들을 한 번에 받아올 수 있음
    underfetching 문제 해결, 요청 횟수 감소
  • 하나의 ednpoint에서 모든 요청을 처리
    하나의 URI에서 모든 요청 가능.

Apollo

특징

  • 백엔드와 프론트엔드 모두 제공
  • 간편하고 쉬운 설정
  • 풍성한 기능들 제공
  • Apollo Server: 백엔드 서버
  • Apollo Client: 프론트엔드 웹

Apollo Client 사용하기

  • 모듈 설치
npm install @apollo/client graphql
  • 모듈 import
// ...
import { ApolloProvider } from '@apollo/client';
import { ApolloClient, InMemoryCache } from '@apollo/client'
// ...
// app.js
// ...
const client = new ApolloClient({
  uri: 'http://localhost:4000',
  cache: new InMemoryCache()
});
// ...
  return (
    <div className="App">
      <ApolloProvider client={client}>
        <header className="App-header">
          <h1>Company Management</h1>
          <nav>
            <ul>
              {NavMenus()}
            </ul>
          </nav>
        </header>
        <main>
          {mainComp[menu]}
        </main>
      </ApolloProvider>
    </div>
  );
//   ...

ApolloClient

REST API의 axios 같은 역할로 해당 uri와 통신을 주고받을 수 있게 해준다.

  • client : GraphQL 서버로와 정보를 주고받을 Apollo Client 객체
  • uri : GraphQL 서버 주소
  • cache : 한 번 받아온 데이터를 다시 받지 않아도 되도록 도와주는 InMemoryCache를 통해 캐시 관리

ApolloProvider

내부 요소를 감싸줌으로써 내부 요소에서 Apollo Client를 통해 서버와 통신을 주고받을 수 있게 해준다.

서버로부터 데이터 받아오기

요청 객체 만들기

// ...
const GET_ROLES = gql`
  query GetRoles {
    roles {
      id
    }
  }
`;
// ...

요청 객체를 사용하여 데이터 받아오기

// ...
  function AsideItems () {
    const { loading, error, data } = useQuery(GET_ROLES);
    if (loading) return <p className="loading">Loading...</p>
    if (error) return <p className="error">Error :(</p>
    //...
  }
// ...
  • loading : 서버에서 정보를 받아오는 동안 표시
  • error : 요청에 오류가 발생할 시 반환
  • data : 요청대로 받아진 정보

데이터 삭제하기

// ...
// delete 요청 변수
const DELETE_TEAM = gql`
  mutation DeleteTeam($id: ID!) {
    deleteTeam(id: $id) {
      id
    }
  }
`
// ...
  function execDeleteTeam () {
    if (window.confirm('이 항목을 삭제하시겠습니까?')) {
      // 함수 실행
      deleteTeam({variables: {id: contentId}})
    }
  }

  const [deleteTeam] = useMutation(
   //요청 변수가 실행되고 이의 결과로 onCompleted가 실행
  DELETE_TEAM, { onCompleted: deleteTeamCompleted })
  
  //onCompleted의 실행 함수
  function deleteTeamCompleted (data) {
    console.log(data.deleteTeam)
    alert(`${data.deleteTeam.id} 항목이 삭제되었습니다.`)
    setContentId(0)
  }
 // ...

☝🏻 데이터는 삭제되었으나 리스트 새로고침이 필요하다면?

const { loading, error, data, refetch } = useQuery(GET_TEMAS)
  • useQuery의 refetch를 사용하면 다시 데이터를 불러오는 작업이 실행된다.
// ...
let refetchTeams
// ...
const { loading, error, data, refetch } = useQuery(GET_TEMAS)
refetchTeams = refetch
// ...
function deleteTeamCompleted (data) {
  // ...
  alert(`${data.deleteTeam.id} 항목이 삭제되었습니다.`)
  refetchTeams()
}
// ...

수정 및 추가도 같은 구조로 진행된다.

Fragment

  • 여러 쿼리에 사용될 수 있는, 재사용 가능한 필드셋
  • 중복을 줄임으로써 전체 코드를 간소화

재사용되는 요소들을 Fragment로 분리

const Names = gql`
  fragment names on People {
    first_name
    last_name
  }
`
const HealthInfo = gql`
  fragment healthInfo on People {
    sex
    blood_type
  }
`
const WorkInfo = gql`
  fragment workInfo on People {
    serve_years
    role
    team
    from
  }
`

쿼리에 적용

const GET_PEOPLE = gql`
  query GetPeople {
  people {
    id
    ...names
    ...healthInfo
    }
  }
  ${Names}
  ${HealthInfo}
`;

얄코님의 유튜브 강좌를 보고 작성되었습니다.
얄코 강좌 바로가기>

profile
깃헙으로 이사중..

0개의 댓글