🌸 GraphQL

GraphQL server 공식문서 참고

ji-hyun 2022. 3. 26. 17:33

How GraphQL

 

GraphQL 은 백엔드 기술의 떠오르는 별입니다. API 설계 패러다임으로 REST를 대체하며 웹 서버의 데이터와 기능을 노출시키는 새로운 표준이 되고 있습니다.

이 튜토리얼에서는 관용적GraphQL 서버를 처음부터 완전히 구축하는 방법을 배웁니다. 다음 기술을 사용할 것입니다.

 

 

  • Apollo Server 2.18 : 손쉬운 설정, 성능, 뛰어난 개발자 경험 등에 중점을 둔 완전한 기능을 갖춘 GraphQL Server입니다 .
  • Prisma : 기존 ORM을 대체합니다. Prisma Client를 사용하여 GraphQL 리졸버 내부의 데이터베이스에 액세스하십시오.
  • GraphQL Playground : 쿼리 및 변형을 전송하여 GraphQL API의 기능을 대화식으로 탐색할 수 있는 "GraphQL IDE"입니다. REST API에 유사한 기능을 제공 하는 Postman 과 다소 유사합니다 . 무엇보다도 GraphQL Playground는 다음과 같습니다.
    • 사용 가능한 모든 API 작업에 대한 포괄적인 문서를 자동 생성합니다.
    • 자동 완성(!) 및 구문 강조와 함께 쿼리, mutation 및 구독을 작성할 수 있는 편집기를 제공합니다.
    • API 작업을 쉽게 공유할 수 있습니다.

 

 

=> 프리즈마 클라이언트를 사용해서 graphQL 리졸버 내부의 데이터베이스에 접근할 수 있다.

 

 

 

 

 

 

 

기대할 수 있는 것

  • 이 튜토리얼의 목표는 Hacker News 클론을 위한 API를 구축하는 것입니다. 다음은 예상되는 사항에 대한 간략한 설명입니다.
  • 서버에 대한 GraphQL 스키마 를 정의하고 해당 리졸버 함수 를 작성 하여 GraphQL 서버가 작동하는 방식에 대한 기본 사항을 배우는 것으로 시작합니다 . 
  • 데이터를 저장하고 유지할 수 없는 서버를 원하는 사람은 아무도 없겠죠? 걱정할 것 없습니다! 다음 으로 Prisma 로 관리할 프로젝트에 SQLite 데이터베이스를 추가할 것 입니다.
  • 사용자가 API에 대해 인증할 수 있도록 하는 가입/로그인 기능을 구현하여 시작합니다. 이를 통해 특정 API 작업에 대한 사용자의 권한을 확인할 수도 있습니다
  • 다음으로 API 소비자가 필터링 및 페이지 매김 기능을 추가하여 API에서 검색하는 항목 목록을 제한하도록 허용합니다.

 

 

 

 

 

 

mkdir hackernews-node
cd hackernews-node
npm init -y

 

package.json => 여기에는 앱에 필요한 모든 종속성과 기타 구성 옵션(예: 스크립트 )이 나열됩니다.

 

 

 

 

 

 

 

npm install apollo-server@^2 graphql@^14.6.0

 

GraphQL 서버 구축을 시작하겠습니다! 

먼저 GraphQL 서버를 생성할 수 있는 위와 같이 두 가지 중요한 종속성을 설치하겠습니다.

 

 

 

 

apollo-server : 모든 기능을 갖춘 GraphQL 서버입니다. Express.js 및 기타 몇 가지 라이브러리를 기반으로 하여 프로덕션용 GraphQL 서버를 구축하는 데 도움이 됩니다.

 

기능 목록은 다음과 같습니다.

  • GraphQL 사양 준수
  • GraphQL 구독을 통한 실시간 기능
  • GraphQL Playground에 대한 즉시 지원
  • Express 미들웨어를 통해 확장 가능
  • GraphQL 스키마에서 사용자 지정 지시문을 해결합니다.
  • 쿼리 성능 추적
  • 모든 곳에서 실행: Vercel, Up, AWS Lambda, Heroku 등을 통해 배포할 수 있습니다.

 

 

 

 

 

 

 

공식문서 코드

공식문서 코드는 다음과 같습니다.

 

const { ApolloServer } = require('apollo-server');

// 1
const typeDefs = `
  type Query {
    info: String!
  }
`

// 2
const resolvers = {
  Query: {
    info: () => `This is the API of a Hackernews Clone`
  }
}

// 3
const server = new ApolloServer({
  typeDefs,
  resolvers,
})

server
  .listen()
  .then(({ url }) =>
    console.log(`Server is running on ${url}`)
  );

 

 

  1. typeDefs상수는 GraphQL 스키마를 정의합니다 ( 자세한 내용은 잠시 후). type 정의의 느낌표는 이 필드가 필수이며  null 이 절대 될 수 없음을 의미합니다 .
  2. resolvers 개체는 GraphQL 스키마 의 실제 구현 입니다. typeDefs 와 resolvers 에서 내부의 type 정의 구조와 어떻게 동일한지 주목하십시오
  3. 마지막으로 스키마와 리졸버가 번들되어 ApolloServer에서 가져온 대상으로 전달됩니다 apollo-server. 이것은 어떤 API 작업이 수락되고 어떻게 해결되어야 하는지 서버에 알려줍니다.

 

 

 

 

 

 

 

리졸버를 구현하고 있으므로 해당 필드의 값을 제어할 수 있습니다. 맞죠?

그렇다면 리졸버 구현에서 실제 정보 문자열 대신 null 을 반환하면 어떻게 될까요? 

 

다음과 같이 업데이트 합니다.

 

const resolvers = {
  Query: {
    info: () => null,
  }
}

 

 

 

 

 

여기서 일어나는 일은 기본 참조 구현이 resolver 의 반환 유형이 GraphQL 스키마의 type 정의를 준수하도록 보장한다는 것입니다. 다르게 말하면 어리석은 실수로부터 당신을 보호합니다!

 

 

이것은 사실 일반적으로 GraphQL의 핵심 이점 중 하나입니다. API가 스키마 정의에 의해 약속된 방식으로 실제로 작동하도록 강제합니다! 이렇게 하면 GraphQL 스키마에 액세스할 수 있는 모든 사람이 API에서 반환되는 API 작업 및 데이터 구조에 대해 항상 100% 확신할 수 있습니다.

 

 

 

이 스키마에는  info 라는 단일 루트 필드만 있습니다. query , mutation 을 GraphQL API로 보낼 때 항상 루트 필드로 시작해야 합니다! 이 경우 루트 필드가 하나만 있으므로 API에서 허용하는 가능한 쿼리는 실제로 하나만 있습니다.

 

 

이제 약간 더 발전된 예를 살펴보겠습니다.

 

type Query {
  users: [User!]!
  user(id: ID!): User
}

type Mutation {
  createUser(name: String!): User!
}

type User {
  id: ID!
  name: String!
}

 

이 경우 세 개의 루트 필드가 있습니다. (users, user on Query, create User on Mutation). 

 

 

이 스키마 정의에서 파생될 수 있는 API 작업은 무엇입니까? 각 API 작업은 항상 루트 필드로 시작해야 한다는 것을 알고 있습니다. 그러나 루트 필드의 type 자체가 다른 객체 유형일 때의 모습을 아직 배우지 못했습니다 . 

 

 

 

 

 

다음은 위의 스키마를 구현하는 GraphQL API 에서 허용하는 작업입니다.

 

# Query for all users
query {
  users {
    id
    name
  }
}

# Query a single user by their id
query {
  user(id: "user-1") {
    id
    name
  }
}

# Create a new user
mutation {
  createUser(name: "Bob") {
    id
    name
  }
}

 

 

주의할 사항이 몇 가지 있습니다.

  • 이 예에서 우리는 항상 id,  name 반환된 User개체를 쿼리합니다. 우리는 잠재적으로 둘 중 하나를 생략할 수 있습니다. 그러나 객체 유형을 조회할 때 선택 세트에서 해당 필드 중 하나 이상을 조회해야 합니다.

 

 

루트 필드는 사용 가능한 API 작업을 정의합니다.

"GraphQL 스키마는 서버의 API를 정의합니다."

 

 

 

 

 


공식문서 코드

 

좀 더 활용 예시를 들어보겠습니다.

이 섹션에서는 Hacker News 클론의 기능을 제공하는 첫 번째 API 작업 (다른 사용자가 게시한 링크 피드 쿼리)을 구현합니다.

 

 

feed 목록을 검색할 수 있는 쿼리를 구현하여 시작하겠습니다 . 

 

1. 새 루트 필드로 graphQL 스키마 확장하기

2. 추가된 필드에 해당하는 리졸버 구현

 

 

이 프로세스를 스키마 기반 개발 또는 스키마 우선 개발 이라고도 합니다 .

 

 

 

 

 

1. 새 루트 필드로 graphQL 스키마 확장하기

 

const typeDefs = `
  type Query {
    info: String!
    feed: [Link!]!
  }

  type Link {
    id: ID!
    description: String!
    url: String!
  }
`
 
 

 

 

 

 

 

2. 추가된 필드에 해당하는 리졸버 구현

 

// 1
let links = [{
  id: 'link-0',
  url: 'www.howtographql.com',
  description: 'Fullstack tutorial for GraphQL'
}]

const resolvers = {
  Query: {
    info: () => `This is the API of a Hackernews Clone`,
    // 2
    feed: () => links,
  },
  // 3
  Link: {
    id: (parent) => parent.id,
    description: (parent) => parent.description,
    url: (parent) => parent.url,
  }
}

 

 

parent

 

첫번째 수준에서는 feed 리졸버를 호출하고 links에 포함된 모든 데이터를 반환합니다. 두번째 실행 수준에서는, 직전의 리졸버 실행 수준에서 반환된 리스트에 포함된 각각의 항목들에 대하여 Link 타입의 리졸버를 호출합니다. 이것이 가능한 이유는 GraphQL 서버는 feed가 Link로 이루어진 리스트를 반환한다는 것을 스키마를 통하여 알기 때문입니다. 아주 영리하죠. 그 결과, Link가 가지는 3개의 리졸버에서 인자로 들어오는 parent 객체는 links 리스트의 각 항목입니다.

 

 

 

 

 

 

 

 

 

다음 쿼리를 전송하여 사용해 보세요.

 

query {
  feed {
    id
    url
    description
  }
}

 

 

 

 

 

응답결과

 

{
  "data": {
    "feed": [
      {
        "id": "link-0",
        "url": "www.howtographql.com",
        "description": "Fullstack tutorial for GraphQL"
      }
    ]
  }
}