Skip to content

Instantly share code, notes, and snippets.

@kbrandwijk
Created November 28, 2017 12:16
Show Gist options
  • Save kbrandwijk/627ceefab8ea61c0b457a64f68b2d251 to your computer and use it in GitHub Desktop.
Save kbrandwijk/627ceefab8ea61c0b457a64f68b2d251 to your computer and use it in GitHub Desktop.
Schema imports
export const finalSchema = `
# import { topExperiences, topHomes, topReservations, featuredDestinations, experiencesByCity } from 'homepage'
# import { viewer } from 'viewer'
# import { signup, login } from 'auth'
# import { addPaymentMethod, book } from 'newmutations'
type Query {
topExperiences: [Experience!]!
topHomes: [Home!]!
topReservations: [Reservation!]!
featuredDestinations: [Neighbourhood!]!
experiencesByCity(cities: [String!]!): [ExperiencesByCity!]!
viewer: Viewer
}
type Viewer {
me: User!
bookings: [Booking!]!
}
type Mutation {
signup(
email: String!
password: String!
firstName: String!
lastName: String!
phone: String!
): User!
login(email: String! password: String!): User!
addPaymentMethod(
cardNumber: String!
expiresOnMonth: Int!
expiresOnYear: Int!
securityCode: String!
firstName: String!
lastName: String!
postalCode: String!
country: String!
): User!
book(
placeId: ID!
checkIn: String!
checkOut: String!
numGuests: Int!
): BookingResult!
}
type BookingResult {
success: Boolean!
}
type ExperiencesByCity {
experiences: [Experience!]!
city: City!
}
type Home {
id: ID!
name: String
description: String!
numRatings: Int!
avgRating: Float!
pictures(first: Int): [Picture!]!
}
type Reservation {
id: ID!
title: String!
avgPricePerPerson: Int!
pictures: [Picture!]!
location: Location!
isCurated: Boolean!
slug: String!
popularity: Int!
}
type Experience {
id: ID!
category: ExperienceCategory
title: String!
location: Location!
pricePerPerson: Int!
reviews: [Review!]!
preview: Picture!
popularity: Int!
}
type Review {
accuracy: Int!
checkIn: Int!
cleanliness: Int!
communication: Int!
createdAt: DateTime!
id: ID!
location: Int!
stars: Int!
text: String!
value: Int!
}
type Neighbourhood {
id: ID!
name: String!
slug: String!
homePreview: Picture
city: City!
featured: Boolean!
popularity: Int!
}
type Location {
id: ID!
lat: Float!
lng: Float!
address: String
directions: String
}
type Picture {
id: ID!
url: String!
}
type City {
id: ID!
name: String!
}
type ExperienceCategory {
id: ID! @isUnique
mainColor: String!
name: String!
experience: Experience
}
type User {
bookings: [Booking!]
createdAt: DateTime!
email: String!
firstName: String!
hostingExperiences: [Experience!]
id: ID!
isSuperHost: Boolean!
lastName: String!
location: Location!
notifications: [Notification!]
ownedPlaces: [Place!]
paymentAccount: [PaymentAccount!]
phone: String!
profilePicture: Picture
receivedMessages: [Message!]
responseRate: Float
responseTime: Int
sentMessages: [Message!]
updatedAt: DateTime!
token: String!
}
type PaymentAccount {
id: ID!
createdAt: DateTime!
type: PAYMENT_PROVIDER
user: User!
payments: [Payment!]!
paypal: PaypalInformation
creditcard: CreditCardInformation
}
type Place {
id: ID! @isUnique
name: String
size: PLACE_SIZES
shortDescription: String!
description: String!
slug: String!
maxGuests: Int!
numBedrooms: Int!
numBeds: Int!
numBaths: Int!
reviews: [Review!]!
amenities: Amenities!
host: User!
pricing: Pricing!
location: Location!
views: PlaceViews!
guestRequirements: GuestRequirements
policies: Policies
houseRules: HouseRules
bookings: [Booking!]!
pictures: [Picture!]
popularity: Int!
}
type Booking {
id: ID! @isUnique
createdAt: DateTime!
bookee: User!
place: Place!
startDate: DateTime!
endDate: DateTime!
payment: Payment!
}
type Notification {
createdAt: DateTime!
id: ID!
link: String!
readDate: DateTime!
type: NOTIFICATION_TYPE
user: User!
}
type Payment {
booking: Booking!
createdAt: DateTime!
id: ID!
paymentMethod: PaymentAccount!
serviceFee: Float!
}
type PaypalInformation {
createdAt: DateTime!
email: String!
id: ID!
paymentAccount: PaymentAccount!
}
type CreditCardInformation {
cardNumber: String!
country: String!
createdAt: DateTime!
expiresOnMonth: Int!
expiresOnYear: Int!
firstName: String!
id: ID!
lastName: String!
paymentAccount: PaymentAccount
postalCode: String!
securityCode: String!
}
type Message {
createdAt: DateTime!
deliveredAt: DateTime!
id: ID!
readAt: DateTime!
}
type Pricing {
averageMonthly: Int!
averageWeekly: Int!
basePrice: Int!
cleaningFee: Int
currency: CURRENCY
extraGuests: Int
id: ID!
monthlyDiscount: Int
perNight: Int!
securityDeposit: Int
smartPricing: Boolean!
weekendPricing: Int
weeklyDiscount: Int
}
type PlaceViews {
id: ID!
lastWeek: Int!
}
type GuestRequirements {
govIssuedId: Boolean!
guestTripInformation: Boolean!
id: ID!
recommendationsFromOtherHosts: Boolean!
}
type Policies {
checkInEndTime: Float!
checkInStartTime: Float!
checkoutTime: Float!
createdAt: DateTime!
id: ID!
updatedAt: DateTime!
}
type HouseRules {
additionalRules: String
createdAt: DateTime!
id: ID!
partiesAndEventsAllowed: Boolean
petsAllowed: Boolean
smokingAllowed: Boolean
suitableForChildren: Boolean
suitableForInfants: Boolean
updatedAt: DateTime!
}
type Amenities {
airConditioning: Boolean!
babyBath: Boolean!
babyMonitor: Boolean!
babysitterRecommendations: Boolean!
bathtub: Boolean!
breakfast: Boolean!
buzzerWirelessIntercom: Boolean!
cableTv: Boolean!
changingTable: Boolean!
childrensBooksAndToys: Boolean!
childrensDinnerware: Boolean!
crib: Boolean!
doorman: Boolean!
dryer: Boolean!
elevator: Boolean!
essentials: Boolean!
familyKidFriendly: Boolean!
freeParkingOnPremises: Boolean!
freeParkingOnStreet: Boolean!
gym: Boolean!
hairDryer: Boolean!
hangers: Boolean!
heating: Boolean!
hotTub: Boolean!
id: ID!
indoorFireplace: Boolean!
internet: Boolean!
iron: Boolean!
kitchen: Boolean!
laptopFriendlyWorkspace: Boolean!
paidParkingOffPremises: Boolean!
petsAllowed: Boolean!
pool: Boolean!
privateEntrance: Boolean!
shampoo: Boolean!
smokingAllowed: Boolean!
suitableForEvents: Boolean!
tv: Boolean!
washer: Boolean!
wheelchairAccessible: Boolean!
wirelessInternet: Boolean!
}`
export const linkingSchema = `
# import { Booking, PaymentAccount } from 'booking'
# import { Place, User } from 'accomodation'
extend type User {
bookings: [Booking]
paymentAccounts: [PaymentAccount]
}
extend type Place {
bookings: [Booking]
}
extend type Booking {
bookee: User,
place: Place
}
extend type PaymentAccount {
user: User
}`
require('dotenv').config()
import * as express from 'express'
import expressPlayground from 'graphql-playground-middleware-express'
import { remoteSchema, schema, resolver, resolvers, serve, use, transform } from 'qewl'
import * as jwt from 'express-jwt'
import { linkingSchema } from './schemas/linkingSchema'
import { linkingResolvers } from './resolvers/linkingResolvers'
import { homepage } from './resolvers/Query/homepage'
import { Viewer } from './resolvers/Viewer'
import { account } from './resolvers/Mutation/account'
import { User } from './resolvers/User'
import { ExperiencesByCity } from './resolvers/ExperiencesByCity'
import { addPaymentMethod } from './resolvers/Mutation/addPaymentMethod'
import { book } from './resolvers/Mutation/book'
import { checkAuthentication } from './utils'
import { Home } from './resolvers/Home'
import { finalSchema } from './schemas/finalSchema'
async function run() {
const app = express()
const graphql = express.Router()
// Add user from Authorization token to context
graphql.use(jwt({ secret: process.env.JWT_SECRET, credentialsRequired: false }))
// Add and link schemas
graphql.use(
// Add accomodation and booking endpoint
remoteSchema({
name: 'accomodation'
uri: process.env.GRAPHCOOL_ACCOMODATION_ENDPOINT,
authenticationToken: () => process.env.GRAPHCOOL_ACCOMODATION_TOKEN
}),
remoteSchema({
name: 'booking'
uri: process.env.GRAPHCOOL_BOOKING_ENDPOINT,
authenticationToken: () => process.env.GRAPHCOOL_BOOKING_TOKEN
}),
// Add linking schema between endpoints
schema({name: 'linking', schema: linkingSchema}),
// Add linking resolvers
resolvers(linkingResolvers)
)
// Add top level fields
graphql.use(
schema({name: 'homepage', schema: `
# import { Experience, Restaurant, Neighbourhood } from 'accomodation'
extend type Query {
topExperiences: [Experience!]!
topHomes: [Home!]!
topReservations: [Restaurant!]!
featuredDestinations: [Neighbourhood!]!
experiencesByCity(cities: [String!]!): [ExperiencesByCity!]!
}
type Home {
id: ID!
name: String
description: String!
numRatings: Int!
avgRating: Float!
pictures(first: Int): [Picture!]!
}
type ExperiencesByCity {
experiences: [Experience!]!
city: City!
}`}),
resolvers(homepage),
resolvers(ExperiencesByCity),
resolvers(Home)
)
// Add Viewer
graphql.use(
schema({name: 'viewer', schema: `
# import { User } from 'accomodation'
# import { Booking } from 'booking'
extend type Query {
viewer: Viewer
}
type Viewer {
me: User!
bookings: [Booking!]!
}`}),
resolvers(Viewer),
)
// Add authentication
graphql.use(
schema({name: 'auth', schema: `
# import { User } from 'accomodation'
extend type Mutation {
signup(email: String!, password: String!, firstName: String!, lastName: String!, phone: String!): User!
login(email: String! password: String!): User!
}
extend type User {
token: String!
}
`}),
resolvers(account),
resolvers(User)
)
// Add custom mutations
graphql.use(
schema({name: 'newmutations', schema: `
extend type Mutation {
addPaymentMethod(
cardNumber: String!
expiresOnMonth: Int!
expiresOnYear: Int!
securityCode: String!
firstName: String!
lastName: String!
postalCode: String!
country: String!
): User!
book(
placeId: ID!
checkIn: String!
checkOut: String!
numGuests: Int!
): BookingResult!
}
type BookingResult {
success: Boolean!
}
`}),
resolver('Mutation.addPaymentMethod', addPaymentMethod),
resolver('Mutation.book', book),
)
// Set up routes that require authentication (could also be done in the resolvers)
graphql.use(
use('Query.viewer', checkAuthentication),
use('Mutation.addPaymentMethod', checkAuthentication),
use('Mutation.book', checkAuthentication)
)
graphql.use(transform(finalSchema))
app.use('/graphql', express.json(), graphql, await serve())
app.use('/playground', expressPlayground({ endpoint: '/graphql' }))
app.listen(3000, () =>
console.log('Server running. Open http://localhost:3000/playground to run queries.')
)
}
run().catch(console.error.bind(console))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment