Last active
April 5, 2018 03:16
-
-
Save jmcneese/b646066ea260a833d38f744373247981 to your computer and use it in GitHub Desktop.
Relay/GraphQL signIn/signOut mutation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
relay.commitUpdate( | |
new SignInMutation({ username, password, viewer }), { | |
onSuccess: ({ signIn: { viewer: { token } } }) => { | |
// do something with the returned token, set it in localStorage or cookies, or whatever | |
}, | |
onFailure: (transaction) => { | |
// handle the failed mutation | |
}, | |
} | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cors from 'cors'; | |
import express from 'express'; | |
import expressGraphql from 'express-graphql'; | |
import schema from 'schema'; | |
const handler = expressGraphql((req) => { | |
let token = null; | |
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { | |
// grab the token out of the headers, if present | |
token = req.headers.authorization.split(' ')[1]; | |
} else if (req.cookies && req.cookies.token) { | |
// use the session cookie, for returning users | |
token = req.cookies.token; | |
} | |
// before you set the token you could decode and verify the JWT here, or do db lookups, or whatever before setting the context | |
return { | |
schema, | |
context: { | |
token, | |
}, | |
}; | |
)); | |
const graphqlRouter = express.Router(); | |
graphqlRouter.use(cors()); | |
graphqlRouter.use('/', handler); | |
export default graphqlRouter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { GraphQLNonNull, GraphQLString } from 'graphql'; | |
import { mutationWithClientMutationId } from 'graphql-relay'; | |
import ViewerType from 'schema/types/viewer'; | |
export default mutationWithClientMutationId({ | |
name: 'SignIn', | |
inputFields: () => ({ | |
username: { | |
type: new GraphQLNonNull(GraphQLString), | |
description: 'The username of the viewer', | |
}, | |
password: { | |
type: new GraphQLNonNull(GraphQLString), | |
description: 'The password of the viewer', | |
}, | |
}), | |
outputFields: () => ({ | |
viewer: { | |
type: ViewerType, | |
description: 'The viewer who is logging in', | |
}, | |
}), | |
mutateAndGetPayload: ({ username, password }, context) => { | |
// do whatever with the input to authenticate the user and generate a JWT, and set the token to context for use in other resolvers | |
const token = 'token here'; | |
context.token = token; | |
return { | |
viewer: { | |
loggedIn: true, | |
token, | |
}, | |
}; | |
}, | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Relay from 'react-relay/classic'; | |
// the SignOut mutation looks almost the same as this | |
export default class SignInMutation extends Relay.Mutation { | |
static fragments = { | |
viewer: () => Relay.QL` | |
fragment on Viewer { | |
id | |
} | |
`, | |
}; | |
getMutation = () => Relay.QL` | |
mutation { signIn } | |
`; | |
getVariables = () => ({ | |
username: this.props.username, | |
password: this.props.password, | |
}); | |
getFatQuery = () => Relay.QL` | |
fragment on SignInPayload { | |
viewer { | |
loggedIn | |
token | |
# other stuff that might change when the viewer logs in | |
} | |
} | |
`; | |
getConfigs = () => [ | |
{ | |
// just to be sure the token comes back in the fat query | |
type: 'REQUIRED_CHILDREN', | |
children: [ | |
Relay.QL` | |
fragment on SignInPayload { | |
viewer { | |
token | |
} | |
} | |
`, | |
], | |
}, | |
{ | |
type: 'FIELDS_CHANGE', | |
fieldIDs: { | |
viewer: this.props.viewer.id, | |
}, | |
}, | |
]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { mutationWithClientMutationId } from 'graphql-relay'; | |
import ViewerType from 'schema/types/viewer'; | |
export default mutationWithClientMutationId({ | |
name: 'SignOut', | |
outputFields: () => ({ | |
viewer: { | |
type: ViewerType, | |
description: 'The viewer who is signing out', | |
}, | |
}), | |
mutateAndGetPayload: (args, context) => { | |
context.token = null; | |
return { | |
viewer: { | |
loggedIn: false, | |
token: null, | |
}, | |
}; | |
}, | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { GraphQLBoolean, GraphQLObjectType, GraphQLNonNull, GraphQLString } from 'graphql'; | |
import jwt from 'jsonwebtoken'; | |
import { nodeInterface } from 'schema/lib/node'; | |
import PersonType from 'schema/types/person'; | |
/** | |
* Viewer type | |
*/ | |
export default new GraphQLObjectType({ | |
name: 'Viewer', | |
description: 'The viewer of the application', | |
interfaces: () => [nodeInterface], | |
fields: () => ({ | |
id: globalIdField('viewers'), | |
loggedIn: { | |
type: new GraphQLNonNull(GraphQLBoolean), | |
description: 'Whether the viewer is logged in', | |
resolve: (root, args, { token }) => { | |
// no token, no person | |
if (!token) { | |
return Promise.resolve(false); | |
} | |
try { | |
// check token validity, and decode if valid | |
const decoded = jwt.verify(token, process.env.SECRET); | |
return Promise.resolve(true); | |
} catch (e) { | |
return Promise.resolve(false); | |
} | |
}, | |
}, | |
person: { | |
type: PersonType, | |
description: 'The person record of the viewer', | |
resolve: (root, args, { db, token }) => { | |
// no token, no person | |
if (!token) { | |
return Promise.resolve({}); | |
} | |
try { | |
// check token validity, and decode if valid | |
const decoded = jwt.verify(token, process.env.SECRET); | |
// get person from db | |
return db.getPersonById(decoded.sub); | |
} catch (e) { | |
// invalid token, no person and destroy token | |
context.token = null; | |
return Promise.resolve({}); | |
} | |
}, | |
}, | |
}), | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment