Skip to content
This repository has been archived by the owner on Nov 10, 2024. It is now read-only.

Latest commit

 

History

History
98 lines (76 loc) · 3.71 KB

using-current-user-viewer-as-root-of-graphql-queries.org

File metadata and controls

98 lines (76 loc) · 3.71 KB

WARNING: This is old and likely obsolete.

Using Current User (Viewer) as root of GraphQL queries

  • published_date: 2017-09-19T21:09
  • :keywords: graphql, graphql-ruby, authorization, viewer rooted graph

I was watching a youtube video by Dan Schafer of Facebook where he talks about a lot of things, with the immedate take-away for me of rooting the graphql query in the current viewer or user of the website (big assumption this is being driven by a user sitting in front of a client.)

The idea makes sense to me, as it’s a way of establishing who is requesting info and be able to authorize the queries and mutations.

For graphql-ruby, this means setting up the Query graph like so:

Types::QueryType = GraphQL::ObjectType.define do
  name "Query"
  field :viewer, Types::ViewerType, "Viewer of data, may be an anonymous user or registered user" do
    resolve ->(_object, _args, context) do
      if context[:current_user].present?
        context[:current_user]
      else
        NullUser.new
      end
    end
  end
end

The viewer type is reflective of the User model in the data store, which is what is contained in the current_user in the context passed in. That value can be obtained in a few ways: some typical to Rails apps, through OAuth, through JWTs, etc. It’s not especially important here how the current user is determined to the graphql system, as it should be. Here we can see that if there is no current user in the context, a “Null User” object is returned.

For sake of clarity, the ViewerType is:

Types::ViewerType = GraphQL::ObjectType.define do
  name "Viewer"
  field :id, !types.ID, hash_key: :uuid
  field :name, !types.String
  field :email, !types.String
  field :my_posts, types[Types::PostType] do
    resolve ->(obj, _, _) { obj.posts }
  end

  field :public_posts, types[Types::PostType] do
    resolve ->(_,_,_){ Post.publised }
  end
  field :all_authors, types[Types::UserType] do
    resolve ->(_,_,_){ User.all }
  end
end

Giving the above a query like:

query Query { viewer { public_posts { title excerpt publishedAt }}}

Will return a JSON object like:

{
  "data" : {
    "viewer": {
      "public_posts": [
        {
          "title": "Some post title",
          "excerpt": "It was a dark and stormy night...",
          "publishedAt": "2017-09-18T12:25:03.005600-05:00"
        },
        {
          "title": "Another post",
          "excerpt": "We were once free to roam the...",
          "publishedAt": "2017-09-18T12:25:03.005600-05:00"
        }
      ]
    }
  }
}

Here’s something I’m doing, which I haven’t seen anywhere else yet.

The application is the canonical micropost system, with users, posts, and (eventually) comments.

Posts belong to Users, Comments belong to both Users and Posts. A rule would be that all published posts are visible to everyone, and these are gathered with the :public_posts field.

Another rule would be that only the post’s author can update, publish, or delete a given post

So, a query from an anonymous user would have the published posts, but my_posts would be an empty set.

Another way to sort this is have multiple root fields in the base query, but this seems frowned on.