https://github.com/apollographql/fullstack-tutorial
clone 받아오기
cd start/server
폴더 경로를 start/server
로 이동 후
npm install
진행
server/src/index.js
require("dotenv").config();
const { ApolloServer } = require("apollo-server");
const typeDefs = require("./schema");
const server = new ApolloServer({ typeDefs });
schema.js
const { gql } = require("apollo-server");
const typeDefs = gql`
# Your schema will go here
`;
module.exports = typeDefs;
const { gql } = require("apollo-server");
const typeDefs = gql`
# Your schema will go here
type Launch {
id: ID!
site: String
mission: Mission
rocket: Rocket
isBooked: Boolean!
}
`;
module.exports = typeDefs;
const typeDefs = gql`
# Your schema will go here
type Launch {
id: ID!
site: String
mission: Mission
rocket: Rocket
isBooked: Boolean!
}
type Rocket {
id: ID!
name: String
type: String
}
type User {
id: ID!
email: String!
trips: [Launch]!
token: String
}
type Mission {
name: String
missionPatch(size: PatchSize): String
}
enum PatchSize {
SMALL
LARGE
}
type Query {
launches: [Launch]!
launch(id: ID!): Launch
me: User
}
type Mutation {
bookTrips(launchIds: [ID]!): TripUpdateResponse!
cancelTrip(launchId: ID!): TripUpdateResponse!
login(email: String): User
}
type TripUpdateResponse {
success: Boolean!
message: String
launches: [Launch]
}
`;
index.js
server.listen().then(() => {
console.log(`
Server is running!
Listening on port 4000
Explore at https://studio.apollographql.com/sandbox
`);
});
server 경로에서 npm start
해줌으로써 실행
datasource/launch.js
const { RESTDataSource } = require("apollo-datasource-rest");
class LaunchAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = "https://api.spacexdata.com/v2/";
}
}
module.exports = LaunchAPI;
resolvers를 만들어야한다.
resolvers에는 쿼리를 만들어야한다.
resolvers를 만들기 위해 데이터를 api 서버로부터 가져온다.
async getAllLaunches() {
const response = await this.get('launches');
return Array.isArray(response)
? response.map(launch => this.launchReducer(launch))
: [];
}
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,
},
};
}
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 })),
);
}
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/sandbox
`);
});
Obejct Relational Mapping DB와 데이터를 매핑해주는 도구
resolvers.js
module.exports = {
Query: {
launches: (_, __, { dataSources }) =>
dataSources.launchAPI.getAllLaunches(),
launch: (_, { id }, { dataSources }) =>
dataSources.launchAPI.getLaunchById({ launchId: id }),
me: (_, __, { dataSources }) => dataSources.userAPI.findOrCreateUser(),
},
};
index.js
const { ApolloServer } = require("apollo-server");
const typeDefs = require("./schema");
const { createStore } = require("./utils");
const resolvers = require("./resolvers"); //highlight-line
const LaunchAPI = require("./datasources/launch");
const UserAPI = require("./datasources/user");
const store = createStore();
const server = new ApolloServer({
typeDefs,
resolvers, //highlight-line
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/sandbox
`);
});
query Query{
launches {
id
}
}
위 코드를 통해 제대로 작동하는지 확인하기.
지금 내가 띄워 논 서버 local서버를 바라보고 있으며 spacex에 요청하여 그것을 받아와 response해준다.
지금 상태에서 쿼리로 Mission에 대한 값을 조회하면 null로 받아온다.
이유는 launch.js launchReducer
에서 small or large 일때만 값을 반환하도록 하였기 때문 그래서 아래의 코드를 resolver.js에 추가해주자.
Mission: {
// The default size is 'LARGE' if not provided
missionPatch: (mission, { size } = { size: "LARGE" }) => {
return size === "SMALL"
? mission.missionPatchSmall
: mission.missionPatchLarge;
},
},
//login
Mutation: {
login: async (_, { email }, { dataSources }) => {
const user = await dataSources.userAPI.findOrCreateUser({ email });
if (user) {
user.token = Buffer.from(email).toString("base64");
return user;
}
},
bookTrips: async (_, { launchIds }, { dataSources }) => {
const results = await dataSources.userAPI.bookTrips({ launchIds });
const launches = await dataSources.launchAPI.getLaunchesByIds({
launchIds,
});
return {
success: results && results.length === launchIds.length,
message:
results.length === launchIds.length
? "trips booked successfully"
: `the following launches couldn't be booked: ${launchIds.filter(
(id) => !results.includes(id)
)}`,
launches,
};
},
cancelTrip: async (_, { launchId }, { dataSources }) => {
const result = await dataSources.userAPI.cancelTrip({ launchId });
if (!result)
return {
success: false,
message: "failed to cancel trip",
};
const launch = await dataSources.launchAPI.getLaunchById({ launchId });
return {
success: true,
message: "trip cancelled",
launches: [launch],
};
},
},
index.js
const isEmail = require("isemail");
context: async ({ req }) => {
// simple auth check on every request
const auth = (req.headers && req.headers.authorization) || "";
const email = Buffer.from(auth, "base64").toString("ascii");
if (!isEmail.validate(email)) return { user: null };
// find a user by their email
const users = await store.users.findOrCreate({ where: { email } });
const user = (users && users[0]) || null;
return { user: { ...user.dataValues } };
},
로그인 후 예약 시 header에 authorization에 값이 비어 있다면 예약을 할 수 없다.