Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add user field to LoginMethodResponse #23

Closed
nicolaslopezj opened this issue Dec 7, 2016 · 17 comments
Closed

Add user field to LoginMethodResponse #23

nicolaslopezj opened this issue Dec 7, 2016 · 17 comments

Comments

@nicolaslopezj
Copy link
Owner

nicolaslopezj commented Dec 7, 2016

We want:

# Type returned when the user logs in
type LoginMethodResponse {
  # Id of the user logged in user
  id: String!
  # Token of the connection
  token: String!
  # Expiration date for the token
  tokenExpires: Float!
  # Logged in user
  user: User!
}

But we would need to define the type User... Maybe pass the type name as an option?

@dbrrt
Copy link
Contributor

dbrrt commented Dec 7, 2016

Maybe the way to go is to simply define a 'User type' schema in resolvers and embedding it in LoginMethodResponse?

@janikvonrotz
Copy link
Contributor

@nicolaslopezj We could pass the user as an option, but how would you pass the custom user query to the client method?

I thought about something different. Let's create a onLogin event and pass a method which queries the logged in user and stores him in the local storage.
Another helpful function to do so would be storeByQuery. The onLogin method is called by loginWith* and createUser.

Here's an example:

import { onLogin, storeByQuery } from 'meteor-apollo-accounts'

onLogin(() => {

  storeByQuery({
    currentUser: `
      currentUser {
        _id
        profile	{
          firstname
          lastname
          name
        }
        emails {
          address
          verified
        }
      }
    `
  }
  )
  
})

The currentUser query resolver would look like this:

currentUser (root, args, context) {
  var { userId } = context ? context : { userId: null }
  if (userId) {
    return Meteor.users.findOne(userId)
  }
}

And is shipped with the Meteor package.

Making this work would require another option on the SchemaTypes function:

${SchemaTypes({
  CreateUserProfileInput: `
    firstname: String!
    lastname: String!
    name: String!
  `
  CustomTypes: `
    type User {
      _id: ID
      emails: [Email]
      profile: UserProfile
    }
    type Email {
      address: String
      verified: Boolean
    }
    type UserProfile {
      firstname: String
      lastname: String
      name: String
    }
  `
})}

Of course there would be a default fallback.

This ways also allows you to extend the user type with other attributes such as Role and still have it in the local storage of the client.

So basically in the end it's possible to do this:

import { user } from 'meteor-apollo-accounts'

user().role
user().profile.firstname

@dbrrt
Copy link
Contributor

dbrrt commented Dec 22, 2016

Is the "StoreByQuery" necessary?
Can't we define an User schema on server that developer can edit if required; e.g. : if User needs to be extended with something like Groups/Roles. I just don't know how is generated this LoginMethodResponse.

@nicolaslopezj
Copy link
Owner Author

Maybe we could assume the app has a User type. @dbrrt wanna make a PR with the changes?

@dbrrt
Copy link
Contributor

dbrrt commented Dec 27, 2016

@nicolaslopezj Yep, I think that the App should have a User type defined for authentication by the developer who can extend it depending his/her needs, and one User type should be enough for this case, and will avoid many confusion.

@dbrrt
Copy link
Contributor

dbrrt commented Dec 31, 2016

Can we imagine something like that :

import userType from '/lib/user.js';

export default gql`
# Type returned when the user logs in
type LoginMethodResponse {
  # Id of the user logged in user
  id: String!
  # Token of the connection
  token: String!
  # Expiration date for the token
  tokenExpires: Float!
  # User Schema type defined in /lib/user.js
  user: User!
}

${userType}

#Other responses Type

`

It does the job, but requires a schema defined for user, the best scenario would be to define a default one, eg :

type User {
  _id: String
  profile: UserProfile
}

# Custom Userprofile
type UserProfile {
  firstname: String!
  lastname: String!
  groups: Groups!
}

# Groups Type
type Groups {
  groups: [Group]
}

# Group Type
type Group {
  group: String!
  role:  String!
}

The schema above should be overridable by the developer by defining one in /lib/user.js (for instance)

@janikvonrotz
Copy link
Contributor

The user schema should be passed as parameter as it's already done with CreateUserProfileInput. Overriding the default schema by defining a file is not a good idea for many reasons (flexibility, file and folder structure, schema centralization, ...).

@dbrrt
Copy link
Contributor

dbrrt commented Jan 2, 2017

@janikvonrotz I don't like it neither, your approach seems way better than defining the User schema in a file.
Have you an idea on how to implement storeByQuery or maybe already tested it?

@janikvonrotz
Copy link
Contributor

@dbrrt No I'm not entirely sure how to do this, I'm also a bit busy with school right now. For now I would focus on parameterizing the SchemaTypes method with the additional user types, create a onLogin event method and use the apollo.query method to query currentUser and save it to the local storage manually. Once done, decide wether storeByQuery would be a useful enhancement.

@dbrrt
Copy link
Contributor

dbrrt commented Jan 2, 2017

so if injecting a storage can work, than can be ok for React-Native too, which is great.
I'll try to implement that after solving storage issues.

@nicolaslopezj
Copy link
Owner Author

It's simpler than it sounds, we have 2 alternatives to have this response:

type LoginMethodResponse {
  # Id of the user logged in user
  id: String!
  # Token of the connection
  token: String!
  # Expiration date for the token
  tokenExpires: Float!
  # User Schema type defined in /lib/user.js
  user: User!
}
  • On every method that returns a LoginMethodResponse add the user (user: Meteor.users.findOne()) to the response object. This will do the fetch for every login, even if the client doesn't requests the user.

  • The other way is to create the resolver for LoginMethodResponse:

{
  LoginMethodResponse: {
    user ({id}) {
      return Meteor.users.findOne(id)
    }
  }
}

But we don't have a option to pass resolvers to the apollo app, only for the mutations. We would need to make a breaking change to the api.

@dbrrt
Copy link
Contributor

dbrrt commented Jan 5, 2017

The problem now is how to store the Custom User schema and its associated sub schemas through GraphQL.

@nicolaslopezj
Copy link
Owner Author

We would just assume that the user has a User type in their apps

@dbrrt
Copy link
Contributor

dbrrt commented Jan 6, 2017

I'd define one by default in the library resolver, that could be used if the user forgot/doesn't override it in his schema.
For now I'm defining it in my schema but the app and it works.

@nicolaslopezj
Copy link
Owner Author

But if we define it in our library the user will have to change the user schema from our settings, not directly in their schema

@META-DREAMER
Copy link
Contributor

I think we should just leave this up to the user to define their own User schema and resolvers and queries. A User type would be something thats used very often in their own queries, and not everyone would have the same shape as the default user object in meteor. For example, in my app, my user schema is:

type User {
    _id: ID!
    username: String
    email: String
    name: String
    picture: String
    bio: String
    social: UserSocial
    usertype: String
    title: String
    looks(skip: Int = 0, limit: Int = 10): [Look]
    shows(skip: Int = 0, limit: Int = 10): [Show]
    savedItems(skip: Int = 0, limit: Int = 20): [SavedItem]
    viewedItems(skip: Int = 0, limit: Int = 20): [SavedItem]
    likedLooks(skip: Int = 0, limit: Int = 20): [LikedLook]
    following: Boolean
}

Where the fields are resolved as follows:

{_id: user._id, username: user.username, email: user.emails[0].address, usertype: user.usertype, social: user.profile.social, name: user.profile.name, bio:user.profile.bio, picture: user.profile.picture}

Having the users schema change without them explicitly defining it as such is not really something we should do.

@dbrrt
Copy link
Contributor

dbrrt commented Jan 19, 2017

@HammadJ I totally agree with that, in the app, we should be able to override a custom type User defined in the library, @nicolaslopezj I didn't test it yet (lack of time).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants