주어진 문자열과 일치하는 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()
를 사용
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
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>
서로 다른 출처(origin)를 가진 주소로 요청이 들어왔을 때 발생할 수 있는 에러
여기서 말하는 출처(origin)란, port 번호까지 포함한 url를 의미
예를 들어 이러한 url(http://localhost:3000/tokens/phone
)에서 http://localhost:3000
을 origin이라고 부름
port 번호가 다른 경우에도 CORS 에러는 발생 → 같은 localhost라도 다른 출처로 인식되기 때문
⇒ 백엔드 서버에서는 응답 헤더의 Access-Control-Allow-Origin
항목에 API에 대해 허용하고자 하는 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()); // 추가된 부분
// ...
코드를 수정할 때마다 서버를 종료하고 다시 시작
→ API 응답을 받아오기 전에 해당 과정을 생략할 수 있도록 도와주는 도구 > nodemon
<
터미널에 ls
명령어를 입력해 현재 위치에 package.json
파일이 있는 것을 확인
yarn add nodemon
node가 아닌 nodemon으로 서버를 실행하게 되면 변경된 소스코드의 저장과 동시에 자동으로 서버의 갱신이 이루어짐
package.json
파일에 scripts
부분을 아래와 같이 작성
// package.json
{
// ...
"scripts": {
"dev": "nodemon index.js"
},
// ...
}
서버를 실행할 때마다 nodemon으로 서버가 실행
yarn dev
지금까지 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
안에 정의한 타입과 일치하는 데이터를 응답으로 보내게 됨
Query
객체 정의
const resolvers = {
Query: {
fetchBoards: () => {
},
},
};
REST-API
에서는 res.send
를 이용해서 데이터 반환
GraphQL-API
는 return
을 사용해 함수를 종료하면서 데이터를 반환
// 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개 이상을 의미
}
`;
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
)의 이름을 가진 인자를 받을 것이며, createBoard
의 return
값도 타입 지정
하나씩 타입을 지정하는 방법도 존재하고 객체 형태로 여러 개의 데이터 타입을 묶어서 사용할 수도 있음
input
을 사용해 입력 받을 데이터의 타입을 객체로 지정
const resolvers = {
Mutation: {
createTokenOfPhone: (_, args) => {
// 1. 휴대폰 번호 자릿수 맞는지 확인하기
const isValid = checkValidationPhone(args.myphone);
// ...
},
},
};