튜토리얼 보러가기
데이터 소스는 스키마 필드를 채우는 데 사용하는 데이터를 보유하는 모든 데이터베이스, 서비스 또는 API이다
GraphQL API는 모든 데이터 소스 조합과 상호 작용할 수 있다
REST API 연결하기
[ src/datasources/launch.js 파일에 아래 코드 붙여 넣기 ]
const { RESTDataSource } = require('apollo-datasource-rest');
class LaunchAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = 'https://api.spacexdata.com/v2/';
}
}
module.exports = LaunchAPI;
데이터 가져오기 방법 작성하기
1. getAllLaunches 방법
모든 SpaceX 실행 목록을 가져 오는 방법이 필요하므로 LaunchAPI 클래스 내부에 getAllLaunches 메서드를 추가한다
[ src/datasources/launch.js 파일에 아래 코드 붙여 넣기 ]
// class LaunchAPI... {
async getAllLaunches() {
const response = await this.get('launches');
return Array.isArray(response)
? response.map(launch => this.launchReducer(launch))
: [];
}
launchReducerREST API의 시작 데이터를 위의 모양으로 변환 하는 메서드를 작성한다.
[ src/datasources/launch.js 파일에 LaunchAPI 클래스 내에 아래 코드를 붙여 넣기 ]
// class LaunchAPI... {
launchReducer(launch) {
return {
id: launch.flight_number || 0,
cursor: `${launch.launch_date_unix}`,
site: launch.launch_site && launch.launch_site.site_name,
mission: {
name: launch.mission_name,
missionPatchSmall: launch.links.mission_patch_small,
missionPatchLarge: launch.links.mission_patch,
},
rocket: {
id: launch.rocket.rocket_id,
name: launch.rocket.rocket_name,
type: launch.rocket.rocket_type,
},
};
}
2. getLaunchById 방법
스키마는 ID로 개별 실행 가져 오기를 지원한다
[ src/datasources/launch.js 파일에 LaunchAPI 클래스 내에 아래 코드 붙여 넣기 ]
// class LaunchAPI... {
async getLaunchById({ launchId }) {
const response = await this.get('launches', { flight_number: launchId });
return this.launchReducer(response[0]);
}
getLaunchesByIds({ launchIds }) {
return Promise.all(
launchIds.map(launchId => this.getLaunchById({ launchId })),
);
}
LaunchAPI 클래스는 완료! 🎉
SpaceX API는 시작 데이터를 가져 오기위한 읽기 전용 데이터 소스이다
사용자 ID 및 좌석 예약과 같은 애플리케이션 데이터를 저장할 수 있는 쓰기 가능한 데이터 소스가 필요하므로
SQLite 데이터베이스에 연결하고 ORM에 Sequelize를 사용한다
사용자 지정 데이터 소스 빌드하기
Apollo는 현재 DataSourceSQL 데이터베이스에 대한 표준 DataSourceSQL 하위 클래스를 제공하지 않는다
따라서 일반 DataSource 클래스 를 확장하여 SQLite 데이터베이스에 대한 사용자 지정 데이터 소스를 만들었다
[ src/datasources/user.js에 등록되어 있는 코드 가져옴( 붙여넣기 노노 ❌) ]
const { DataSource } = require('apollo-datasource');
const isEmail = require('isemail');
class UserAPI extends DataSource {
constructor({ store }) {
super();
this.store = store;
}
/**
* This is a function that gets called by ApolloServer when being setup.
* This function gets called with the datasource config including things
* like caches and context. We'll assign this.context to the request context
* here, so we can know about the user making requests
*/
initialize(config) {
this.context = config.context;
}
/**
* User can be called with an argument that includes email, but it doesn't
* have to be. If the user is already on the context, it will use that user
* instead
*/
async findOrCreateUser({ email: emailArg } = {}) {
const email =
this.context && this.context.user ? this.context.user.email : emailArg;
if (!email || !isEmail.validate(email)) return null;
const users = await this.store.users.findOrCreate({ where: { email } });
return users && users[0] ? users[0] : null;
}
async bookTrips({ launchIds }) {
const userId = this.context.user.id;
if (!userId) return;
let results = [];
// for each launch id, try to book the trip and add it to the results array
// if successful
for (const launchId of launchIds) {
const res = await this.bookTrip({ launchId });
if (res) results.push(res);
}
return results;
}
async bookTrip({ launchId }) {
const userId = this.context.user.id;
const res = await this.store.trips.findOrCreate({
where: { userId, launchId },
});
return res && res.length ? res[0].get() : false;
}
async cancelTrip({ launchId }) {
const userId = this.context.user.id;
return !!this.store.trips.destroy({ where: { userId, launchId } });
}
async getLaunchIdsByUser() {
const userId = this.context.user.id;
const found = await this.store.trips.findAll({
where: { userId },
});
return found && found.length
? found.map(l => l.dataValues.launchId).filter(l => !!l)
: [];
}
async isBookedOnLaunch({ launchId }) {
if (!this.context || !this.context.user) return false;
const userId = this.context.user.id;
const found = await this.store.trips.findAll({
where: { userId, launchId },
});
return found && found.length > 0;
}
}
module.exports = UserAPI;
[ src/datasources/user.js DataSource 하위 클래스 설명 ]
-
initialize: 서브 클래스에 모든 구성 옵션을 전달하려면 이 메서드를 구현하며 UserAPI 클래스는 nitialize를 사용하여 API의 컨텍스트에 액세스한다
-
this.context: 그래프 API의 컨텍스트는 GraphQL 요청의 모든 리졸버 에서 공유되는 객체로 컨텍스트가 사용자 정보를 저장하고 공유하는 데 유용하다
-
캐싱: RESTDataSource 클래스가 내장 캐시를 제공하지만 일반 DataSource 클래스는 제공하지 않는다
[ 데이터 베이스에서 데이터를 가져오고 업데이트 하는 데 사용하는 몇 가지 방법 ]
-
findOrCreateUser({ email }): 데이터 베이스에 주어진 email로 사용자를 찾거나 만든다
-
bookTrips({ launchIds }): launchIds 배열에 있는 개체를 가져와 로그인 한 사용자를 위해 예약한다
-
cancelTrip({ launchId }): launchIds가 있는 개체를 가져와 로그인 한 사용자의 실행을 취소한다
-
getLaunchIdsByUser(): 로그인 한 사용자에 대해 예약 된 모든 여행을 반환한다
-
isBookedOnLaunch({ launchId }): 로그인 한 사용자가 특정 출발에 여행을 예약했는지 여부를 확인한다
Apollo Server에 데이터 소스 추가하기
dataSources 옵션을 ApolloServer 생성자에 전달한다
이 옵션은 새로 인스턴스화 된 데이터 소스를 포함하는 개체를 반환하는 함수이다
[ src/index.js 파일의 코드를 아래 코드로 전체 바꿔주기 ]
const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');
const { createStore } = require('./utils');
const LaunchAPI = require('./datasources/launch');
const UserAPI = require('./datasources/user');
const store = createStore();
const server = new ApolloServer({
typeDefs,
dataSources: () => ({
launchAPI: new LaunchAPI(),
userAPI: new UserAPI({ store })
})
});
server.listen().then(() => {
console.log(`
Server is running!
Listening on port 4000
Explore at https://studio.apollographql.com/dev
`);
});
데이터 소스를 Apollo Server에 연결 완료! 🎉
'개발이야기 > Etc.' 카테고리의 다른 글
PICO-8 판타지 비디오 게임 콘솔 TO THE MOON 🌕 (0) | 2021.03.11 |
---|---|
기획자, 디자이너, 개발자 협업은 어떻게 해야하나? (0) | 2021.03.04 |
Apollo 튜토리얼 - 스키마 만들기 (0) | 2021.02.04 |
modal과 popup 차이 (0) | 2021.02.03 |
어도비 너무 비싸? Adobe 모든 플랜 저렴하게 싸게 구매하는 법! (1) | 2021.02.01 |