React application using Apollo to request a GraphQL API.
.eslintignore:
public
.cache
package-lock.jsoneslintrc.json:
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"no-unused-vars": "warn"
}
}package.json:
{
"dependencies": {
"@apollo/client": "^3.3.9",
"graphql": "^15.5.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"eject": "react-scripts eject",
"wait:msg": "echo Waiting... 5 seconds! (Please save and close all opened tabs - Press Ctrl+C to Exit)",
"git:deploy": "npm run git:merge && npm run git:push",
"wait": "npm run wait:msg && sleep 5",
"git:push": "git push origin dev && git push origin master",
"git:merge": "git status && npm run wait && git checkout master && git merge dev && git checkout dev"
},
"eslintConfig": {
"extends": [
"react-app"
]
}
}App.js
import React from 'react';
import './App.css';
import logo from './logo.jpg';
import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';
import Launches from './components/Launches';
const client = new ApolloClient({
uri: 'http://localhost:5000/graphql',
cache: new InMemoryCache(),
});
function App() {
return (
<ApolloProvider client={client}>
<div className="App">
<div className="container">
{/* Logo */}
<img id="logo" src={logo} alt="SpaceX" />
<Launches />
</div>
</div>
</ApolloProvider>
);
}
export default App;components/LaunchItem.js:
import React from 'react';
import { launchType } from '../types';
const Launch = ({ launch }) => {
const {
flight_number,
mission_name,
launch_success,
launch_date_local,
} = launch;
return (
<div className="card card-body mb-3">
<div className="row">
<div className="col-md-9">
<h4>Misson: {mission_name}</h4>
<p>Date: {launch_date_local}</p>
<span style={{ color: `${launch_success ? 'green' : 'red'}` }}>
{launch_success ? 'Success' : 'Failed'}
</span>
</div>
<div className="col-md-3 d-flex justify-content-end">
<button className="btn btn-primary">
Details
</button>
</div>
</div>
</div>
);
};
Launch.propTypes = {
launch: launchType,
};
export default Launch;components/Launches.js:
import { gql, useQuery } from '@apollo/client';
import React from 'react';
import Launch from './LaunchItem';
const LAUNCHES_QUERY = gql`
query LaunchesQuery {
launches {
flight_number
mission_name
launch_success
launch_date_local
}
}
`;
export const Launches = () => {
const { loading, error, data } = useQuery(LAUNCHES_QUERY);
return (
<div>
<h1 className="display-4 my-3">Launches</h1>
{loading && <h4>Loading...</h4>}
{error && <p>Error :{error.message}</p>}
{/* Launches list */}
{data &&
data.launches.map((launch, i) => (
<Launch key={`launch_${i}_${launch.flight_number}`} launch={launch} />
))}
</div>
);
};
export default Launches;types/index.js: propTypes
import { number, string, bool, shape } from 'prop-types';
// Rocket Type
export const rocketType = shape({
rocket_id: string.isRequired,
rocket_name: string.isRequired,
rocket_type: string,
});
// Launch Type
export const launchType = shape({
flight_number: number.isRequired,
mission_name: string.isRequired,
launch_success: bool,
launch_date_local: string,
launch_year: string,
rocket: rocketType
});Node.JS server using Express framework.
package.json:
{
"main": "server.js",
"scripts": {
"start": "node server.js",
"server": "nodemon server.js",
"client": "npm start --prefix client",
"dev": "concurrently \"npm run server\" \"npm run client\""
},
"dependencies": {
"axios": "^0.21.1",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-graphql": "^0.12.0",
"graphql": "^15.5.0"
},
"devDependencies": {
"concurrently": "^5.3.0",
"nodemon": "^2.0.7"
}
}server.js:
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const cors = require('cors');
const schema = require('./schema');
const app = express();
// Allow cross origin
app.use(cors());
// Add GraphQL endpoint
app.use(
'/graphql',
graphqlHTTP({
schema,
graphiql: true,
})
);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`App listening on port ${PORT}!`));**schema.js:
const axios = require('axios');
const {
GraphQLObjectType,
GraphQLInt,
GraphQLString,
GraphQLBoolean,
GraphQLList,
GraphQLSchema,
} = require('graphql');
// Rocket Type
const RocketType = new GraphQLObjectType({
name: 'Rocket',
fields: () => ({
rocket_id: { type: GraphQLString },
rocket_name: { type: GraphQLString },
rocket_type: { type: GraphQLString },
}),
});
// Launch Type
const LaunchType = new GraphQLObjectType({
name: 'Launch',
fields: () => ({
flight_number: { type: GraphQLInt },
mission_name: { type: GraphQLString },
launch_year: { type: GraphQLString },
launch_date_local: { type: GraphQLString },
launch_success: { type: GraphQLBoolean },
rocket: { type: RocketType },
}),
});
const SpaceXApiURL = 'https://api.spacexdata.com/v3';
// Root query
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
launches: {
type: new GraphQLList(LaunchType),
resolve(parent, args) {
return axios.get(`${SpaceXApiURL}/launches`).then((res) => res.data);
},
},
launch: {
type: LaunchType,
args: {
flight_number: { type: GraphQLInt },
},
resolve(parent, args) {
return axios
.get(`${SpaceXApiURL}/launches/${args.flight_number}`)
.then((res) => res.data);
},
},
rockets: {
type: new GraphQLList(RocketType),
resolve(parent, args) {
return axios.get(`${SpaceXApiURL}/rockets`).then((res) => res.data);
},
},
rocket: {
type: RocketType,
args: {
id: { type: GraphQLString },
},
resolve(parent, args) {
return axios
.get(`${SpaceXApiURL}/rockets/${args.id}`)
.then((res) => res.data);
},
},
},
});
module.exports = new GraphQLSchema({
query: RootQuery,
});