GraphQL VS REST API

shorry·2022년 6월 19일
0

Frontend

목록 보기
3/8

📌GraphQL


  • 페이스북에서 만든 쿼리 언어(Query Language)
  • 그와 동시에 쿼리에 대한 데이터를 받을 수 있는 런터임이기도 하다.

✔️GraphQL의 특징


  • API서버에서 엄격하게 정의된 endpoint 들에 요청하는 대신, 한번의 요청으로 정확히 가져오고 싶은 데이터를 가져올 수 있게 도와주는 쿼리를 보낼수 있다.
  • Frontend와 Backend의 협업 방식에 많은 변화를 가져올 수 있습니다. Backend에서의 많은 로직을 Frontend로 분산할 수 있다.
  • GraphQL spec을 이행하기만 하면 어떤 특정 언어에 종속되지 않고 사용할 수 있다. (go, JAVA, JS, Python, Ruby 등 모든 곳에 사용할 수 있다.)

✔️GraphQL 의 목적 (SQL 과의 차이)


  • 페이스북에 의해서 REST API 문제를 해결하기 위해 만들어졌다.
    (REST API 설명부분에 자세히 다룰 예정)
  • Structed Query Language(이하 sql)은 데이터베이스 시스템에 저장된 데이터를 효율적으로 가져오는 것이 목적이고, GraphQL(이하 gql)은 웹 클라이언트가 데이터를 서버로 부터 효율적으로 가져오는 것이 목적이다.
  • sql의 문장(statement)은 주로 백앤드 시스템에서 작성하고 호출 하는 반면, gql의 문장은 주로 클라이언트 시스템에서 작성하고 호출 한다.

✔️GraphQL은 보통 어디에 쓰이나요?

  • 같은 API를 쓰더라도 필요로하는 정보가 사용자마다 다를 수 있고, 사용하는 기기들마다 다를 수 있고, 또는 그 외의 추가적인 상황에 따라 다를 수 있는데, 그런 서비스들에서는 효율적이다.

✔️GraphQL Operation Type

  • Query - 데이터 조회
  • Mutation - 데이터 수정
  • subscription - 실시간 애플리케이션 구현을 위해 사용

GraphQL 참고영상

(추가) GraphQL과 함께쓰면 좋은 Apollo

  • GraphQL을 쉽게 사용하도록 도와주는 라이브러리
  • apollo client 와 apollo server 를 제공한다.
  • 공식 홈페이지에서 apollo client는 상태관리 라이브러리로 react redux를 apollo server는 REST API 를 대체할 수 있을 것이라고 소개하고 있다.

📌REST API


  • Representational State Transfer API
  • 여러개의 URL을 활용하여 작동한다.
  • 모든 URL은 고유하고, 각기 다른 데이터를 제공한다.
  • HTTP 통신규약에 맞춰 API를 요청할때 어떠한 요청에 어떠한 URI를 사용할지에 대한 형식
  • 각 요청이 어떤 동작이나 정보를 위한 것인지지를 그 요청의 모습 자체로 추론이 가능하다.
  • 해당 버튼을 누르면 해당 음료가 나오는 자판기와 같다.

✔️REST API 의 가장 큰 2가지 문제점

  • Over Fetching
    ex) 숙소에 대한 정보를 받아오려고 하는데, 숙소에 대한 모든 정보가 아니라 특정 정보들만을 추려서 받아오고자 할때, REST API는 새로운 API를 만들거나 불필요한 정보들 까지 다 받아와야 한다.
  • Under Fetching
    ex) 학교에서 1반에 대한 정보와 1반 학생들에 대한 정보를 받아오고자 할 때, REST API는 2번 호출을 해야 한다. 횟수도 문제지만, 비동기로 짜는 코드는 1번의 요청보다 더 복잡해진다.

✔️그렇다면 REST API 는 언제 쓰는가?

  • 받아야하는 항목들이 많고, 확실히 정해진 경우에는 REST API가 유리하다.

REST API 참고영상

📌만드는 서비스에 맞게 어떤걸 사용할지 결정해야하는가??


  • 결정 할 필요가 없다!!
  • 백엔드 서버 하나에 Rest API , GraphQL을 둘 다 구현해 놓으면 된다.
  • 각 정보랑 요청마다 유리한걸로 선택해서 OR 그냥 두 가지 방법으로 모두 구현해 놓으면 된다.

📌GraphQL, Restful API 비교


GraphQLRestful API
Resource에 대한 형태 정의와 데이터 요청방법이 완전히 분리되어 있다.Resource에 대한 형태 정의와 데이터 요청방법이 연결되어 있다.
Resource에 대한 정보만 정의하고, 필요한 크기와 형태는 client단에서 요청 시 결정Resource의 크기와 형태를 서버에서 결정
GraphQL Schema가 Resource를 나타내고 Query, Mutation 타입이 작업의 유형을 나타낸다.URI가 Resource를 나타내고 Method가 작업의 유형을 나타낸다.
한번의 요청에서 여러 Resource에 접근할 수 있다.여러 Resource에 접근하고자 할 때 여러 번의 요청이 필요하다.

📌GraphQL 구현예시 (node.js + express)


✔️server 구현

let express = require('express');
let graphqlHTTP = require('express-graphql');
let { buildSchema } = require('graphql');

// express 서버 생성
let app = express();

// 해당 uri의 미들웨어를 통해 graphQL의 요청을 받을 준비 완료
app.use("/graphql", graphqlHTTP({
	schema: schema,
	rootValue: resolver,
  	graphiql: true,
}));

app.listen(4000, () => console.log('Now browse to localhost:4000/graphql'));

✔️일반적인 데이터 조회 요청

📜요청

# pizza_buns 테이블에 데이터들을 해당하는 컬럼들로만 호출
query {
	pizza_buns {
		pb_name,
		size,
		bread,
		sauce,
		topping
	}
}

# pizza_bun 에서 idx가 4번째인 데이터의 해당하는 컬럼들만 호출
query {
	pizza_bun(pb_idx: 4) {
		pb_name,
		size,
		bread,
		sauce,
		topping
	}
}

# pizza_buns 테이블과 , pizza_bun 2개의 테이블을 원하는 컬럼만 호출
query {
	req1: pizza_buns {
    	pb_name,
        size,
    }
    req2: pizzz_bun(pb_idx: 1) {
    	pb_name,
        size,
        bread
    }
}

📜schema

let schema = buildSchema(`
	type Query {
		pizza_buns: [PizzaBun]
		pizza_bun[pb_idx: Int]: PizzaBun
	}
	
	type PizzaBun {
		pb_idx: ID,
		pb_name: String,
		size: Int,
		bread: String,
		sauce: String,
		topping: String,
	}
`};

📜resolver

let resolver = {
	pizza_buns: () => {
		return [ {
			"pb_idx": "1",
			"pb_name": "sausage",
			"size": 6,
			"bread": "wheat",
			"sauce": "tomato",
			"topping": "sausage"
		}, {
			"pb_idx": "2",
			"pb_name": "seafood",
			"size": 7,
			"bread": "italian",
			"sauce": "arrabiata",
			"topping": "shirimp"
		} ]
	}
}

// 위의 방법으로 하드코딩 하거나
// SQL 쿼리문 , noSQL , 다른서버의 Rest API 요청 등도 가능하다

let resolver = {
	pizza_buns: async () => {
		return await new Promise((resolve) => {
			pool.getConnection(function(err, connection) {
				connection.query(
					'SELECT * FROM pizza_bun',
					(err, results) => {
						connection.release();
						if (err) throw err;
						resolove(results);
					})
				})
			});
		},
	pizza_bun: async ({pb_idx}) => {
		return await new Promise((resolve) => {
			pool.getConnection(function(err, connection) {
				connection.query(
					'SELECT * FROM pizza_bun WHERE pb_idx = ?',
					[pb_idx],
					(err, results) => {
						connection.release();
						if (err) throw err;
						resolove(results);
					})
				})
			});
		},
}

✔️수정 요청을 보낼 때 (예시는 create),

📜요청

mutation {
	create_pizza_bun (input: {
		pb_name: "spicy",
		size: 5,
		bread: "parmesan oregano",
		sauce: "pomodoro",
		topping: "peperoncino"
	}) {
		pb_idx
	}
}

📜schema

type Mutation {
	create_pizza_bun(input: PizzaBunInput): Int
}

input PizzaBunInput {
	pb_name: String,
	size: Int,
	bread: String,
	sauce: String,
	topping: String
}

📜resolver

create_pizza_buns: async ({input}) => {
	const insertResultData = await new Promise((resolove) => {
		pool.getConnection(function(err, connection) {
			connection.query(
				'INSERT INTO pizza_bun (pb_name, size, bread, sauce, topping)'
				+ 'VALUES (?, ?, ?, ?, ?)',
				[input.pb_name, input.size, input.bread, input.sauce, input.topping],
				(err, results, fileds) => {
					connection.release();
					if (err) throw err;
					resolove(results);
				}
			)
		})
	})
	return { pb_idx: insertResultData.insertID }
}

📌Reference

profile
I'm SHORRY about that

0개의 댓글