GraphQL vs REST

Hunter Joe·2025년 8월 20일

해당 게시글은 GraphQL vs. REST의 원문을 번역했음을 미리 알립니다.

wikipedia

GraphQL은 페이스북이 2012년 개발 → 2015 공개한 데이터 질의어

  • REST 및 부속 웹서비스 아키텍처를 대체 할 수 있다.
  • 클라이언트는 필요한 데이터의 구조를 지정할 수 있다.
    → 서버는 정확히 동일한 구조로 데이터를 반환
  • GraphQL은 클라이언트가 어떤 데이터가 필요한지 명시할 수 있게 해주는 강타입 언어
  • 불필요한 데이터를 받게 되거나 필요한 데이터를 받지 못하는 문제를 피할 수 있다.

NOTE
1. REST 아키텍처

  • REST는 HTTP를 활용해 리소스를 주고받는 가장 흔한 아키텍쳐 스타일
  • e.g GET /users/1
  • 엔드포인트가 자원(Resource)단위로 고정되어 있고 클라이언트가 원하는 데이터를 맞춰서 가져오기 어렵다는 단점이 있음

2. 부속 웹서비스 아키텍처

  • SOAP (Simple Object Access Protocol) → XML 기반 메시징
  • RPC (Remote Procedure Call) → 원격 프로시저 호출 기반
  • OData 등 특정 표준 API 프로토콜

📌 개요

GraphQL은 서버에 정의된고정된 엔드포인트를 사용하는 대신 한 번의 요청으로 원하는 데이터를 정확하게 가져오는 쿼리를 전송할 수 있으며 팀 프로젝트에서 FE와 BE의 협업을 원할하게 만들어 줄 수 있다.

하지만 실제로 이 두 기술 모두 HTTP 요청을 전송하고 결과를 수신하는 과정을 포함하며
GraphQ에는 REST 모델의 여러 요소가 내장되어 있다.

📌 자원, Resource

REST

REST의 핵심 개념은 자원(Resource)이다 각 리소스는 URL로 식별되며, URL로 GET요청을 보내 리소스를 가져온다.
요즘 대부분의 API가 JSON을 사용하므로 JSON응답을 받을 가능성이 높다

e.g

// GET /books/1 

{
  "title": "Black Hole Blues",
  "author": { 
    "firstName": "Janna",
    "lastName": "Levin"
  }
  // ... more fields here
  // "author"를 별도의 리소스로 반환합니다.
}

REST에서 주의해야 할 점은 리소스의 유형 또는 형태와 해당 리소스를 가져오는 방식이 서로 결합되어 있다는 것이다.
REST 문서에서 위 내용을 언급할 때는 book endpoint라고 부를 수 있다.

GraphQL(GQL)

GraphQL은 REST의 book endpoint라고 불리는 것과 다른 부분이 있다.
GQL에서는 이 두 개념이 완전히 분리되어 있기 때문이다.

e.g Book, Author

type Book {
  id: ID
  title: String
  published: Date
  price: String
  author: Author
}

type Author {
  id: ID
  firstName: String
  lastName: String
  books: [Book]
}

사용 가능한 데이터 종류는 설명했지만, 이 설명은 클라이언트에서 해당 객체를 가져오는 방법에 대해서는 전혀 설명하지 않고 있다. 이것이 REST와 GraphQL의 핵심적인 차이점 중 하나이다.
→ 특정 리소스에 대한 설명은 해당 리소스를 가져오는(fetch) 방식과 연관되어 있지 않다.

특정 book 또는 author에 접근하려면 Query 타입의 스키마를 작성해야 한다.

e.g

type Query {
  book(id: ID!): Book
  author(id: ID!): Author
}

이제 REST 요청과 비슷한 요청을 보낼 수 있지만 이번에는 GraphQL을 사용해야 합니다.

// GET /graphql?query={ book(id: "1") { title, author { firstName } } }

{
  "title": "Black Hole Blues",
  "author": {
    "firstName": "Janna",
  }
}

차이점

REST와 GraphQL 둘 다 URL을 통해서 요청할 수 있고, 동일한 JSON 응답 형식을 반환받을 수 있다는 점에서는 동일하지만

GQL 쿼리를 담은 URL은 우리가 어떤 리소스를 요청하는지 그리고 그 중 어떤 필드가 필요한지를 명확하게 지정한다.
또한 관련된, author리소스를 포함할지 말지는 서버 개발자가 정해주는 것이 아니라
API를 사용하는 클라이언트가 직접 결정한다.

더 중요한 점은 리소스의 정체성(book, author)이 그걸 가져오는 방식과 결합되어 있지 않다는 것이다.
book객체를 여러 다른 쿼리 방식으로 요청할 수 있으며, 매번 필요한 필드만 다르게 가져올 수도 있다.

결론

  • 유사점: 둘 다 리소스에 대한 개념을 가지고 있으며 해당 리소스에 대한 ID를 지정할 수 있습니다.
  • 유사점: 둘 다 URL이 포함된 HTTP GET 요청을 통해 가져올 수 있습니다.
  • 유사점: 둘 다 요청에서 JSON 데이터를 반환할 수 있습니다.
  • 차이점: REST에서는 호출하는 엔드포인트가 해당 객체의 ID입니다. GraphQL에서는 ID가 객체를 가져오는 방식과 별개입니다.
  • 차이점: REST에서는 리소스의 형태와 크기가 서버에 의해 결정됩니다. GraphQL에서는 서버가 사용 가능한 리소스를 선언하고 클라이언트는 필요한 리소스를 요청합니다.

📌 URL Routes vs GraphQL Schema

API는 예측 가능하지 않으면 유용하지 않습니다. API를 사용할 때는 일반적으로 프로그램의 일부로 사용하게 되며, 해당 프로그램은 무엇을 호출할 수 있고 어떤 결과를 받을 것으로 예상해야 그 결과를 바탕으로 작업을 수행할 수 있다.

API에서 가장 중요한 부분 중 하나는 접근 간능한 항목에 대한 설명입니다. API 문서를 읽을 때 이러한 내용을 배우게 되는데 GraphQL 인트로스펙션과 Swagger와 같은 REST API 스키마 시스템을 사용하면 이 정보를 프로그래밍 방식으로 검토할 수 있다.

오늘날의 REST API에서 API는 일반적으로 엔드포인트 목록으로 설명됩니다.

REST

GET /books/:id 
GET /authors/:id 
GET /books/:id/comments 
POST /books/:id/comments

해당 API의 형태는 선형적이라고 할 수 있습니다.(접근할 수 있는 항목의 목록이 있다는 것)
데이터를 검색하거나 저장할 때 가장 먼저 떠오르는 질문은 "어떤 엔드포인트를 호출 해야 할까?"
입니다.

NOTE
해석할 때 Linear이라는 단어가 잘 이해가 안됐는데 다음과 같다.
경로가 나열형,목록형이라서 직선적으로 탐색한다는 뉘앙스

GraphQL

GraphQL에서는 위에서 설명한 대로 URL을 사용하여 API에서 사용 가능한 항목을 식별하는 대신
GraphQL 스키마를 사용합니다.'

type Query {
  book(id: ID!): Book
  author(id: ID!): Author
}

type Mutation {
  addComment(input: AddCommentInput): Comment
}

type Book { ... }
type Author { ... }
type Comment { ... }
input AddCommentInput { ... }

비슷한 데이터셋을 REST 라우트로 다루는 경우와 비교했을 때, 몇가지 흥미로운 차이점이 있다.
1. REST에서는 URL에 다른 HTTP 메서드(GET, POST, PUT등)을 사용해서 읽기/쓰기 동작을 구분하지만
GraphQL은 요청 타입을 다음과 같이 구분한다.

  • Query : 읽기
  • Mutation : 쓰기
query { ... }
mutation { ... }

Query타입의 필드들을 보면 REST 라우트와 꽤 잘 대응된다는 걸 알 수 있습니다.
왜냐 이 Query라는 특별한 타입이 데이터에 접근하는 진입점(Entry Point) 역할을 하기 때문에 GraphQL에서 엔드포인트 URL과 가장 비슷한 개념이라고 볼 수 있다.

GraphQL에서는 스키마에 정의된 관계를 따라가며 하나의 복잡한 쿼리 안에서 추가 데이터를 연쇄적으로 가져올 수 있지만 REST에서는 그걸 하려면

  • 여러 번 요청을 보내거나
  • 아예 서버에서 관련 데이터를 처음부터 포함해주거나
  • 혹은 URL에 특별한 파라미터를 붙여서 응답 모양을 바꾸도록 만들어야 합니다

결론

REST에서는 접근 가능한 데이터 공간이 엔드포인트의 선형 목록으로 설명되고 GraphQL에서는 관계가 있는 스키마로서 설명됩니다.

유사점 (Similar):

  • REST API의 엔드포인트 목록은 GraphQL API의 Query와 Mutation 타입에 있는필드 목록과 비슷합니다. 둘 다 데이터에 접근하는 진입점(entry point)입니다.

  • 두 방식 모두 API 요청이 데이터를 읽는(read) 용도인지, 쓰는(write) 용도인지 구분할 방법을 가지고 있습니다.

차이점 (Different):

GraphQL에서는 스키마에 정의된 관계를 따라 한 번의 요청으로 엔트리 포인트에서 연관된 데이터까지 탐색할 수 있습니다. REST에서는 관련 리소스를 가져오려면 여러 엔드포인트를 호출해야 합니다.

GraphQL에서는 Query 타입의 필드와 다른 타입의 필드 사이에 본질적인 차이가 없습니다. 단지 Query 타입만 쿼리의 루트에서 접근 가능할 뿐이죠. 예를 들어 GraphQL에서는 어떤 필드든 인자를 가질 수 있습니다. 반면 REST에는 중첩 URL(nested URL)을 표현하는 일급(first-class) 개념이 없습니다.

REST에서는 쓰기 요청을 지정할 때 GET 대신 POST 같은 다른 HTTP 메서드를 사용합니다. GraphQL에서는 쿼리 키워드(Query → Mutation)만 바꿔주면 됩니다.

📌 Route Handlers vs. Resolvers

그렇다면 실제로 API를 호출하게 될 경우 어떻게 될까요?
일반적으로 API는 요청을 받은 서버에서 특정 코드를 실행합니다.
1. 계산을 수행하거나
2. DB의 데이터를 불러오거나
3. 다른 API를 호출하거나
4. 실제로 무엇이든 실행 가능
→ 핵심은 외부에서 API가 무엇을 하는지 알 필요가 없다는 것입니다.
하지만 REST와 GraphQL 모두 내부 API 내부를 구현하는 표준적인 방식을 가지고 있으며, 두 기술을 비교하여 두 기술의 차이점을 파악하는 것이 유용합니다.

REST

Node.js의 express를 사용한 Hello World 예제

app.get('/hello', function(req,res) {
	res.send('Hello World')
}

/hello에서 문자열을 반환하는 엔드포인트를 생성 'Hello World!'
이 예제를 통해 REST API 서버에서 HTTP 요청의 수명 주기를 확인할 수 있다.

  • 서버는 요청을 수신하고 HTTP 메서드와 URL 경로를 검색한다.
  • API 라이브러리는 서버 코드에 의해 등록된 함수에 대한 동사와 경로를 일치시킴
  • 이 함수는 한 번 실행되고 결과를 리턴
  • API 라이브러리는 결과를 직렬화하고 적절한 응답 코드와 헤더를 추가한 후 클라이언트로 재전송

GraphQL

GraphQL은 매우 유사한 방식으로 작동하며 동일한 hello world예제 에서는 사실상 동일합니다.

const resolvers = {
  Query: {
    hello: () => {
      return 'Hello world!';
    },
  },
};

보시는 것처럼, 특정 URL에 대응하는 함수를 제공하는 대신 특정 타입의 필드에 대응하는 함수를 제공하고 있습니다.
여기서는 Query 타입의 hello 필드에 해당하는 함수죠.

GraphQL에서 이렇게 필드를 실제로 구현하는 함수를 리졸버(resolver)라고 부릅니다.

요청을 보내기 위해선 다음과 같은 Query가 필요합니다:

query {
  hello
}

서버가 GraphQL 요청을 받으면 다음과 같은 일이 일어납니다.

  1. 서버는 요청을 수신하고 GraphQL 쿼리를 검색

  2. Query를 순회(traverse)하면서 각 필드마다 리졸버(resolver)를 호출

    • 이번 경우에는 query타입 안의 hello라는 단 하나의 필드만 있습니다.
  3. 해당 리졸버 함수가 실행되고 결과값을 반환

  4. GraphQL 라이브러리와 서버가 이 결과를 쿼리의 모양(shape)에 맞게 응답에 첨부해 반환

그러면 다음과 같은 결과가 반환됩니다.

{ "hello": "Hello, world!" }

여기 재미있는 트릭이 하나 있습니다. 우리는 같은 필드를 두 번 호출할 수도 있습니다!

query {
  hello
  secondHello: hello
}

이 경우에도 위와 동일한 라이프사이클이 실행되지만 별칭(alias)을 사용해 같은 필드를 두 번 요청했기 때문에 hello 리졸버가 실제로는 두 번 호출됩니다.
물론 이건 다소 인위적인 예시이지만 핵심은 하나의 요청 안에서 여러 필드가 실행될 수 있으며, 동일한 필드도 쿼리의 여러 지점에서 여러 번 호출될 수 있다는 점입니다.

중첩 리졸버(nested resolver) 예시

{
  Query: {
    author: (root, { id }) => find(authors, { id: id }),
  },
  Author: {
    posts: (author) => filter(posts, { authorId: author.id }),
  },
}

이러한 리졸버들은 다음과 같은 쿼리를 처리할 수 있습니다:

query {
  author(id: 1) {
    firstName
    posts {
      title
    }
  }
}

리졸버들의 집합 자체는 사실상 flat하지만
각 리졸버가 서로 다른 타입에 연결되어 있기 때문에 이렇게 중첩된 쿼리 형태를 조합할 수 있는 것입니다.

요약
별칭(alias)을 쓰면 같은 필드를 여러 번 호출 가능 → 리졸버도 그만큼 실행됨.
리졸버 구조는 flat 하지만, 타입에 매핑되므로 결과적으로는 중첩 쿼리를 만들 수 있음

  • REST 왕복과 단일 GraphQL 요청으로 리소스를 가져오는 것에 대한 예시 이미지

결론

결국 REST와 GraphQL API는 모두 네트워크를 통해 함수를 호출하는 멋진 방법일 뿐입니다. REST API 구축에 익숙하다면 GraphQL API 구현도 크게 다르지 않을 것입니다.
하지만 GraphQL은 여러 번의 왕복 없이 여러 관련 함수를 호출할 수 있다는 점에서 큰 장점을 가지고 있습니다.

유사점 (Similar):

  • REST의 엔드포인트와 GraphQL의 필드 모두 결국 서버 쪽의 함수를 호출하게 됩니다.

  • REST와 GraphQL 모두 보통은 프레임워크와 라이브러리에 의존해서 네트워킹과 같은 세부적인 보일러플레이트 코드를 처리합니다.

차이점 (Different):

  • REST에서는 각 요청이 보통 정확히 하나의 라우트 핸들러 함수를 호출합니다. 반면 GraphQL에서는 하나의 쿼리가 여러 리졸버를 호출해서 여러 리소스를 포함하는 중첩된 응답을 만들어냅니다.

  • REST에서는 응답(response)의 구조를 서버가 직접 만들어야 합니다. GraphQL에서는 쿼리의 모양(shape)에 맞게 GraphQL 실행 라이브러리가 응답의 구조를 자동으로 조립합니다.

참고 문헌

https://www.apollographql.com/blog/graphql-vs-rest

profile
Async FE 취업 준비중.. Await .. (취업완료 대기중) ..

0개의 댓글