모각코 7회차(5.10)

기먼지·2023년 5월 13일
0

인생작

목록 보기
7/9

GraphQL

frontend

Document.getElementById()

주어진 문자열과 일치하는 id 속성을 가진 요소를 찾아 이를 나타내는 Element 객체를 반환

Document.getElementById().value는 무조건 string을 리턴

<head>
	<script>
		function check() {
			const myphone = document.getElementById('phoneNum').value;
		}
	</script>
</head>
<body>
	휴대폰 번호: <input type="text" id="phoneNum"/>
	<button onclick="check()">인증하기</button>
</body>

ID가 없는 요소에 접근하려면 Document.querySelector()를 사용

Axios

Apollo 서버는 GraphQL-API를 제공하는 서버를 개발할 수 있게 도와주는 패키지, 기존에 Node.js에서 사용하는 Express와 역할이 비슷

HTML 파일에서는 axios를 이용하려면 <script> 태크를 사용해서 다운로드, 이러한 방식을 CDN(Contents Delevery Network)라고 함 ↔ 이전에는 postman을 통해 API를 테스트

unpkg CDN 코드를 가져와 <head> 태그 안에 추가

<script scr="https://unpkg.com/axios/dist/axios.min.js"></script>
❓ 엔드포인트 : 네트워크에 연결하고 네트워크를 통해 통신하는 모든 디바이스 → API가 두 시스템(어플리케이션)이 소통할 수 있게 하는 프로토콜의 총집합이라면, 엔드포인트는 API가 서버에서 리소스에 접근할 수 있게 하는 URL

Untitled

axios를 이용하여 post API로 요청을 보내기 위해 아래와 같이 입력

소괄호 안에는 요청을 보내고자 하는 url을 입력

http 요청, req 안의 body에 담아 보내기 위해 중괄호로 감싼 코드를 추가

API 응답을 받기 위해 뒤에 .then() 코드를 추가

응답을 res라는 이름으로 받아옴

<script>
	// ...
	axios
		.post('http://localhost:3000/tokens/phone', {
			myphone: myphone,
	  })
		.then((res) => {
			console.log(res);
		});
</script>

CORS(Cross-Origin-Resource-Sharing)

서로 다른 출처(origin)를 가진 주소로 요청이 들어왔을 때 발생할 수 있는 에러

여기서 말하는 출처(origin)란, port 번호까지 포함한 url를 의미

예를 들어 이러한 url(http://localhost:3000/tokens/phone)에서 http://localhost:3000을 origin이라고 부름

port 번호가 다른 경우에도 CORS 에러는 발생 → 같은 localhost라도 다른 출처로 인식되기 때문

⇒ 백엔드 서버에서는 응답 헤더의 Access-Control-Allow-Origin 항목에 API에 대해 허용하고자 하는 Origin을 담는 방식으로 CORS 에러를 방지

  • 직접 응답 헤더에 Origin을 적어주는 방식
  • CORS 미들웨어 라이브러리 사용
yarn add cors

모든 origin에서 들어오는 요청을 허용

보안과 관련해 특정 origin만을 허용하도록 설정해야 한다면, app.use(cors({origin: ‘허용할 사이트’}))

// index.js

import cors from 'cors';
// ...

const app = express();

app.use(express.json());
app.use(cors());  // 추가된 부분
// ...

Nodemon

코드를 수정할 때마다 서버를 종료하고 다시 시작

→ API 응답을 받아오기 전에 해당 과정을 생략할 수 있도록 도와주는 도구 > nodemon <

터미널에 ls 명령어를 입력해 현재 위치에 package.json 파일이 있는 것을 확인

yarn add nodemon

node가 아닌 nodemon으로 서버를 실행하게 되면 변경된 소스코드의 저장과 동시에 자동으로 서버의 갱신이 이루어짐

package.json 파일에 scripts 부분을 아래와 같이 작성

// package.json

{
	// ...
	"scripts": {
		"dev": "nodemon index.js"
	},
	// ...
}

서버를 실행할 때마다 nodemon으로 서버가 실행

yarn dev

apollo-server

지금까지 Rest-API를 사용하기 위해 express를 사용해 서버를 띄움

Graph-API를 사용해보기 위해 express와 비슷한 역할을 해주는 apollo-server를 사용

아래 명령어를 통해 백엔드 서버 구동 환경을 구성한 뒤, apollo-server와 graphql을 설치

yarn init
yarn add apollo-server graphql

express와 같이 서버를 열어준 뒤 .then() 내부의 내용을 실행

// express
app.listen(3000);

// apollo-server
server.listen().then({ url }) => {
	console.log(`🚀 Server ready at ${url}`);
});

서버를 열어주기 위해 서버를 정의해주는 코드 작성

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

resolvers 는 이전에 express 서버를 사용할 때 보았던 api와 같은 역할을 함

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

// apollo-server
const resolvers = {
	Query: {
		hello: () => 'Hello, World',
	},
};

typeDefs는 type 지정을 도와주는 역할

hello 라는 이름의 Query 요청이 들어오면, String 타입의 데이터를 응답으로 돌려줄 것이라는 정보를 설정

만약 hello 라는 API가 숫자 타입 데이터를 리턴하려 한다면 지정된 타입과 일치하지 않기 때문에 서버가 구동되지 않음

const typeDefs = gql`
	type Query {
		"A simple type for getting started!"
		hello: String
	}
`;

express의 경우 swagger를 통해 api-docs를 직접 작성해 주었는데 graphql의 경우 typeDefs가 자동으로 생성해 줌

http://localhost:3000/graphql 주소로 접속하여 apollo-server를 띄울 수 있음

요청이 들어오면 서버를 구성하는 resolvers 객체의 내부를 들여다 보고, Query, Mutation에 해당하는 객체를 찾게 됨

이후 우리의 경우, Query 객체를 탐색하여 안에 정의되어 있는 API 함수(hello)가 실행됨

결과적으로 API 함수인 hello는 우리가 express에서 res로 응답을 보내듯이 return을 통해 응답을 전달

이때, typeDefs에서 type Query 안에 정의한 타입과 일치하는 데이터를 응답으로 보내게 됨

GraphQL-API

fetchBoards API

Query 객체 정의

const resolvers = {
	Query: {
		fetchBoards: () => {
	
		},
	},
};

REST-API에서는 res.send를 이용해서 데이터 반환

GraphQL-APIreturn을 사용해 함수를 종료하면서 데이터를 반환

// REST-API
res.send(result);

// GraphQL-API
return result;

배열 안에 여러 개의 객체 데이터 타입을 하나하나 지정해줘야 함

각 객체의 property를 어떠한 key타입으로 구성할 것인지 작성

객체 안 요소들의 타입을 모두 지정해 주었다면 API 반환값의 타입을 지정

const typeDefs = gql`
  type BoardReturn {
    number: Int
    writer: String
    title: String
    contents: String
  }

  type Query {
    # fetchBoards: BoardReturn => 객체 1개를 의미
    fetchBoards: [BoardReturn]  # => 배열 안에 객체 1개 이상을 의미
  }
`;

createBoard API

Mutation 객체 정의

생성된 함수를 통하여 입력값을 받아올 수 있음

const resolvers = {
	Mutation: {
		createBoard: (parent, args, context, info) => {
		
		},
	},
};
  • parent : 부모 타입 resolver에서 반환된 결과를 가진 객체
  • args : 쿼리 요청 시 전달된 parameter를 가진 객체
  • context : GraphQL의 모든 resolver가 공유하는 객체로서 로그인 인증, 데이터베이스 접근 권한 등에 사용
  • info : 명령 실행 상태 정보를 가진 객체

REST-API에서는 요청 데이터를 확인하기 위해 매개변수로 req를 사용

GraphQL-API 에서는 4개의 매개변수 중 요청 데이터를 확인 가능한 args를 사용하여 입력값을 가져옴, 사용하지 않는 매개변수는 _(언더바)로 선언

API를 요청하는 사용자가 항상 지정된 타입을 준수하여 요청을 진행할 수 있도록 강제하는 요청 데이터의 타입을 지정

const typeDefs = gql`
	input CreateBoardInput {
    writer: String
    title: String
    contents: String
  }

  type Mutation {
    # createdBoard(writer: String, title: String, contents: String): String  # => 입력값을 낱개로 받아오는 것을 의미
		createBoard(createBoardInput: CreateBoardInput!): String  # => 입력값을 객체로 받아오는 것을 의미
  }
`;

총 세 개(writer, title, contents)의 이름을 가진 인자를 받을 것이며, createBoardreturn 값도 타입 지정

하나씩 타입을 지정하는 방법도 존재하고 객체 형태로 여러 개의 데이터 타입을 묶어서 사용할 수도 있음

input을 사용해 입력 받을 데이터의 타입을 객체로 지정

createTokenOfPhone API 생성

const resolvers = {
	Mutation: {
		createTokenOfPhone: (_, args) => {
			// 1. 휴대폰 번호 자릿수 맞는지 확인하기
			const isValid = checkValidationPhone(args.myphone);
		
		// ...
		},
	},
};
profile
열심히 굴러가기 !

0개의 댓글