Register Meteor, can't add a username

I’m doing a register form and i want to add a username to “profile.name”.

but i can’t add it, i had to create in my collection schema a username attribute if i want the operation to be done.

don’t know what i’m doing wrong.

The password is posted , the email too, but the username no.

async function register() {

  let credentials= {
   
    email: req.query.email,
    password: req.query.password,
    username: req.query.username
  }
    return await Meteor.call('createuser', credentials, (err, res) => {
      if (err) {
        console.log(err)
      }
      else {  
        res.status(403).res.json(res);
      }
    }
    )
  }
  let RegisterTheUser = register();
})

A few things wrong here, and you haven’t provided enough code for us to see what you’re doing:

  1. Is this on the client or server? (I’m guessing server because of req, res)
  2. Where does req/res come from? Connect Handler callback? Express?
  3. Which code generates the request?
  4. What happens in your method?
  5. If this is the server, why are you using a method at all?
  6. Why are you awaiting the Meteor.call? It doesn’t return a promise.
  7. If res is an instance of ServerResponse, then res.status(403).res.json(res) is an error.
  8. Why are you sending a response directly in this function?
  9. Why are you declaring a function just to call it afterwards
  10. What are you doing with RegisterTheUser? Why assign it?
  11. Are you aware that register returns a Promise?
1 Like

Thank you for your reply.

  • It’s a Post Request using express.
  • I’m testing it on a REST Client.
  • I’m doing the await because if i do a normal function i get an error of bindEnvironement.
app.post('/register', (req, res, next) => {
  let credentials= {
   
    email: req.query.email,
    password: req.query.password,
    username: req.query.username
  }
    return  Meteor.call('createuser', credentials, (err, res) => {
      if (err) {
        console.log(err)
      }
      else {  
        send(res);
      }
    }
    )
})

Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.

The method should add a user, but only post the email + password and not the username.

I’m having trouble understanding what you mean by “The method should add a user, but only post the email + password and not the username.”

Are you saying that req.query.username is empty? Or that your method isn’t doing anything with it?


You can fix the Fiber error by doing exactly what it says in the error message: wrap the callback in a Meteor.bindEnvironment like so:

app.post('/register', Meteor.bindEnvironment((req, res, next) => {
  let credentials= {
    email: req.query.email,
    password: req.query.password,
    username: req.query.username
  }
    return  Meteor.call('createuser', credentials, (err, res) => {
      if (err) {
        console.log(err)
      }
      else {  
        send(res);
      }
    }
    )
}))

Is there a specific reason you’re using a separate express app instead of using Meteor’s WebApp?

With WebApp.connectHandlers you can write express-like handlers and have them executed with the full Meteor context:

WebApp.connectHandlers.use('/register', (req, res, next) => {
  if (req.method !== 'POST') return next();
  const credentials= {
    email: req.query.email,
    password: req.query.password,
    username: req.query.username
  }
  Meteor.call('createuser', credentials, (err, res) => {
    if (err) return console.log(err);

    res.writeHead(201); // 201 is HTTP for created
    res.end();
  });
});
1 Like

The method isn’t posting the value of the username.
I had to add

 username:{
        type:String
    },

on my users.js ( collections )

My problem is that i want to store the value of req.query.username on

profile: {
type: Object,
optional: true
},
“profile.name”: {
type: String,
},

profile.name

Are you saying that you have a schema connected to the collection?
Are you using collection2 for automatic validation?

If the error is clearly in the method, why haven’t you posted the method’s code.
Further, since this is on the server, why are you using a Method at all? Why not use a standard function?

This is exactly why I asked for more code.

1 Like
>  createUser : function (credentials) {
>     check(credential, Object)
>     // First we check if the User already exist and if he has PW
>     const USER = Accounts.findUserByEmail(credentials.email)
>     if (USER !== undefined && (USER.services === undefined || USER.services.password === undefined || USER.services.password.bcrypt === undefined)) {
>       Accounts.setPassword(USER._id, credentials.password)
>       result = 'newPassword'
>     } else {
>       // user account creation (via the app)
>       result = Accounts.createUser(credentials) 
>     
>    }
>     return result

This is my method.

Would you mind answering the other questions?

1 Like

I followed your first suggestion and it worked with an error
` url must be absolute and start with http:// or https

It’s doing the post but sending me an error.

And yes i have a schema connected to the collection.

Can you post the schema?

Which suggestion was that, and where is the error coming from, is it from the mystery send function?

1 Like

I edited the code with the bindEnv like you said.

Here is my Schema

let Schemas = {}

Schemas.User = new SimpleSchema({
    createdAt: {
        type: Date
    },

    // Services
    services: {
        type: Object,
        optional: true
    },
    "services.password": {
        type: Object,
        optional: true
    },
    "services.password.bcrypt": {
        type: String,
        optional: true
    },
    "services.resume": {
        type: Object,
        blackbox: true,
        optional: true
    },

    // Emails
    emails: {
        type: Array,
        optional: true
    },
    "emails.$": {
        type: Object
    },
    "emails.$.address": {
        type: String,
        regEx: SimpleSchema.RegEx.Email
    },
    "emails.$.verified": {
        type: Boolean
    },

    // Name
    profile: {
        type: Object,
        optional: true
    },
    "profile.name": {
        // optional:true,
        type: String,
    },
    // Features (Activated or not)
    "profile.features": {
        type: Object,
        optional: true,
        blackbox: true
    },

    pushIds: {
        type: [String],
        optional: true
    },

    // Roles
    roles: {
        type: [String],
        optional: true,
        blackbox: true
    },


})

Meteor.users.attachSchema(Schemas.User)

Ah okay I think I understand now

The easiest way to set profile.name to the username is to pass it into Accounts.createUser
The docs specify that Accounts.createUser accepts an options object which includes the profile

You can do so in your method code:

createUser : function (credentials) {
  check(credential, Object)
  // First we check if the User already exist and if he has PW
  const USER = Accounts.findUserByEmail(credentials.email)
  if (USER !== undefined && (USER.services === undefined || USER.services.password === undefined || USER.services.password.bcrypt === undefined)) {
    Accounts.setPassword(USER._id, credentials.password)
    result = 'newPassword'
  } else {
    // user account creation (via the app)
    credentials.profile = { name: credentials.username }, // <--- Just assign profile before passing to createUser
    result = Accounts.createUser(credentials);
  
  }
  return result

I strongly recommend including username in your schema as well, since Accounts will look for it

1 Like

Working like a charm thank you soo much.

The post is runing well but unfortunatly i got

[Error: url must be absolute and start with http:// or https://]

Whatever that error is, it’s source isn’t in any of the code you’ve posted

Is there a way to get ride of it and just return what i’ve posted ?

maybe i should change something here

  return  Meteor.call('createuser', credentials, (err, res) => {
      if (err) {
        console.log(err)
        
      }
      else {  
        res.json(req.credentials)
      }
    }

Sure. Why return the credentials though? Surely just sending a status code is enough