I used the email-password template to setup my graphcool server with user authentication. I want to add a property for “name” when signing up a new user. I added name to the User model and updated the signup.graphql and signup.ts code as shown below.
I get an error when running the createUser mutation which says “name is not defined”. I’m not sure what the problem is. Any help is greatly appreciated!
signup.graphql
extend type Mutation {
signupUser(email: String!, password: String!, name: String): SignupUserPayload
}
signup.ts
interface EventData {
email: string
password: string
name: string
}
const SALT_ROUNDS = 10
export default async (event: FunctionEvent<EventData>) => {
console.log(event)
try {
const graphcool = fromEvent(event)
const api = graphcool.api('simple/v1')
const { email, password } = event.data
if (!validator.isEmail(email)) {
return { error: 'Not a valid email' }
}
// check if user exists already
const userExists: boolean = await getUser(api, email)
.then(r => r.User !== null)
if (userExists) {
return { error: 'Email already in use' }
}
// create password hash
const salt = bcrypt.genSaltSync(SALT_ROUNDS)
const hash = await bcrypt.hash(password, salt)
// create new user
const userId = await createGraphcoolUser(api, email, hash, name)
// generate node token for new User node
const token = await graphcool.generateNodeToken(userId, 'User')
return { data: { id: userId, token } }
} catch (e) {
console.log(e)
return { error: 'An unexpected error occured during signup.' }
}
}
async function getUser(api: GraphQLClient, email: string): Promise<{ User }> {
const query = `
query getUser($email: String!) {
User(email: $email) {
id
}
}
`
const variables = {
email,
}
return api.request<{ User }>(query, variables)
}
async function createGraphcoolUser(api: GraphQLClient, email: string, password: string, name: string): Promise<string> {
const mutation = `
mutation createGraphcoolUser($email: String!, $password: String!, $name: String) {
createUser(
email: $email,
password: $password,
name: $name
) {
id
}
}
`
const variables = {
email,
password: password,
name: name
}
return api.request<{ createUser: User }>(mutation, variables)
.then(r => r.createUser.id)
Found the answer. I was missing name from this line here..
const { email, password } = event.data
Changing to this solved it
const { email, password, name } = event.data
Related
I'm trying to setup a Apollo 3 local state with react. For an unknown reason my query does not work when I try to read a custom type (isAuthenticated query works well). Can you please help me to understand I literaly explored all the documentation and the link on internet about local state management.
Thank you
cache.js
import { InMemoryCache, makeVar, gql } from '#apollo/client'
export const isAuthenticatedVar = makeVar(!!localStorage.getItem('token'))
export const userVar = makeVar("")
export const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
isAuthenticated: {
read() {
return isAuthenticatedVar()
}
},
user: {
read() {
return userVar()
},
__typename: 'User',
}
}
}
}
})
export const IS_AUTHENTICATED = gql`
query IS_AUTHENTICATED {
isAuthenticated #client
}
`
export const GET_LOCAL_USER = gql`
query GET_LOCAL_USER {
user #client
}
`
typedej.js
import { gql } from '#apollo/client'
export const typeDef = gql`
extend type User {
id: ID!
name: String!
surname: String!
email: String!
password: String!
phone: String!
adress: Adress!
isAdmin: Boolean!
isCoach: Boolean!
isManager: Boolean!
}
extend type Query {
isAuthenticated: Boolean!
user: User!
}
`
export default typeDef
test.js
const login = (email, password) => {
const emailLower = email.toLowerCase()
client.query({
query: LOGIN,
variables: { email: emailLower, password: password }
})
.then(result => {
console.log(result)
localStorage.setItem('token', result.data.login.token)
localStorage.setItem('userId', result.data.login.user.id)
isAuthenticatedVar(true)
userVar({ ...result.data.login.user})
console.log('USER VAR SETUP')
///Console.log show that userVar contains an object with all User data
console.log(userVar())
var test
try{
//test return NULL object
test = client.readQuery({ query: GET_LOCAL_USER}).user
}catch(error) {
console.log(error)
}
console.log('FETCH QUERY userVar')
console.log(test)
navigate("/")
})
.catch(error => {
console.log(error)
})
}
Tried several ways but can't find how to resolve this. I don't understand why documentation don't explain how to use with Object Type
I am trying to implement a search query to help me search by name or category. I need help with only the backend part of it which is setting up the resolver and the index which im not sure if I m doing it right
Resolver.js
//search for single user
user: async ({_id}) => {
try {
const foundUser = await User.findOne({_id: _id})
return foundUser;
} catch (err){
throw err;
}
},
//search for all users
users: async () => {
try{
const users = await User.find()
return users;
} catch(err) {
throw err;
}
},
I want to be able to search all users with the role "Star" and do the search only on those users. Not really sure where to go from here
Index.js
type User {
_id: ID!
username: String
password: String
name: String
role: String
enterCategory: String
}
//not sure if search is right
type RootQuery {
user(_id: ID!): User!
users: [User!]!
searchStars(search: String): [Users]!
}
Index.js
searchCategories(search: String): [User]!
Resolver
searchCategories: async ({ search }) => {
try {
const users = await User.find()
return users.filter(x => x.enterCat === search);
} catch (err) {
throw err;
}
}
I am building login module in my app, For the first time i am using TypeScript so i dont know what to do with that problem.
I have an controller to handle login and User model, I'll paste my code down below.
In User model file i have static function to handle login stuff and my app is crashing.
I am getting error Property 'login' does not exist on type 'Model<any, any, any>
So if someone knows what's going on here please help me =]
import express, {Request, Response} from 'express'
import ErrorHandler from '../app/Handlers/ErrorHandler';
import { User } from '../model/User';
export const signup_post = async (req: Request, res: Response) => {
let {email, password} = req.body
try{
const user = await User.create({
email,
password
})
res.status(201).json({ user: user.email });
}
catch(err){
const errors = ErrorHandler.handleErrors(err);
res.status(400).json({ errors });
}
}
export const login_post = async (req: Request, res: Response) => {
let {email, password} = req.body
try {
const user = await User.login(email, password);
user.save();
}
catch (err) {
console.log(err)
const errors = ErrorHandler.handleErrors(err);
res.status(400).json({ errors });
}
}
import mongoose, { mongo } from 'mongoose';
import bcrypt from 'bcrypt';
import validator from 'validator'
const userSchema = new mongoose.Schema({
email: {
type: String,
required: [true, 'Please enter an email'],
unique: true,
lowercase: true,
validate: [validator.isEmail, 'Please enter a valid email'],
},
password: {
type: String,
required: [true, 'Please enter an password'],
minlength: [6, 'Minimum password length is 6 characters']
},
})
interface User {
email: string;
password: string;
}
userSchema.pre<User>('save', async function (next) {
this.password = this.password + "1"
next();
})
// static method to login user
userSchema.statics.login = async function(email, password) {
const user = await this.findOne({ email });
if(user) {
const auth = await bcrypt.compare(password, user.password);
if(auth) {
return user;
}
throw Error('incorrect password')
}
throw Error('incorrect email');
}
export const User = mongoose.model('user', userSchema)
So, you should just describe your model using interface. E.g.:
// instead of 'interface User'
export interface UserDocument {
email: string;
password: string;
}
export interface UserModel extends mongoose.Model<UserDocument> {
login(email: string, password: string): UserDocument;
}
...
const User: UserModel = mongoose.model<UserDocument, UserModel>("user", userSchema);
I'm trying to make a mutation request to my graphql api but I'm getting an invalid value error. I'm using graphql codegen with typescript and react on my front end. I directly copied my working graphql mutation that I created on graphql playground. Codegen isn't giving any errors when I generate, typescript isn't giving me any errors and I have checked my syntax like 10 times but I can't for the life of me figure out why it's going wrong.
error code: GRAPHQL_VALIDATION_FAILED
error message: "Argument "data" has invalid value {email: $email, username: $username, password: $password, confirmPassword: $confirmPassword}."
My backend resolver looks like this
#Mutation(() => LoginResponse)
async signupLocal(
#Arg("data") signupLocalInput: SignupLocalInput,
#Ctx() { res }: MyContext
): Promise<LoginResponse> {
const user = await signupLocalService(signupLocalInput);
sendRefreshToken(res, createRefreshToken(user));
return {
accessToken: createAccessToken(user),
user,
};
}
My frontend graphql mutation looks like this
mutation SignupLocal(
$email: String!
$username: String!
$password: String!
$confirmPassword: String!
) {
signupLocal(
data: {
email: $email
username: $username
password: $password
confirmPassword: $confirmPassword
}
) {
accessToken
}
}
And my implementation looks like this
const [signupLocal] = useSignupLocalMutation();
const onSubmit = async (data: FormData) => {
console.log(data);
const { email, username, password, confirmPassword } = data;
const response = await signupLocal({
variables: { email, username, password, confirmPassword },
});
console.log(response);
};
I’m trying to do a mutation and I keep getting an error about data being null on the React side. However, if I try the same mutation in the GraphQL console it works. Also, I know the endpoint is working because I can Query data with no problem.
Everything
Server code (resolver):
async signup(parent, args, ctx, info) {
// lowercase their email
args.email = args.email.toLowerCase();
// hash their password
const password = await bcrypt.hash(args.password, 10);
// create the user in the database
const user = await ctx.db.mutation.createUser({
data: {
...args,
password,
}
}, info);
return user;
}
Mutation (React Side)
mutation signupUser($email: String!, $password: String!, $name: String!) {
signup(email: $email, password: $password, name: $name) {
__typename
id
email
password
name
}
}
TypeError: Cannot read property 'data' of undefined
at Mutation._this.onMutationCompleted (react-apollo.esm.js:477)
at react-apollo.esm.js:434
Also here is a snippet of my Mutation on the component
<Mutation
mutation={signUpUserMutation}
onCompleted={(user) => {
handleClose();
}}
onError={(error) => {
console.log(error)
setOpen(true);
}}
>
{signup => (
<Form
onSubmit={async (values, { setSubmitting }) => {
await signup({
variables: {
name: values.name,
email: values.email,
password: values.password,
},
});
setSubmitting(false);
}}
>
{({
values, errors, handleChange, handleBlur, isSubmitting,
}) => (
In your schema
type User {
id: Int
name: String
email: String
password: String
}
type Response {
status: Boolean
message: String
data: User
}
type Mutation {
signUp(name: String!, email: String!, password: String!) : Response
}
On Mutation resolver signUp function
async signUp(parent, args, { db }, info) {
// lowercase their email
args.email = args.email.toLowerCase();
// hash their password
const password = await bcrypt.hash(args.password, 10);
// create the user in the database
const data = {
...args,
password,
}
const user = await db.mutation.createUser(data, info);
return user;
}
in database mutation createUser function you can access like that
const createUser = async ({ name, email, password }, info) => {
try {
// Code to save user information in database
return { status: true,
message: "User registration successful. You can login now.",
data: createdUser
}
} catch(e) {
return { status: false, message: e.message, data: null }
}
}
And your query
mutation signupUser($email: String!, $password: String!, $name: String!) {
signup(email: $email, password: $password, name: $name) {
status
message
data {
id
email
password
name
}
}
}