Community

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
dgrobani
Community Member

Experimental GraphQL API?

Jump to solution

While reviewing our Feature Options today, I was excited to notice for the first time one called "GraphQL API." It's marked beta and described as "EXPERIMENTAL GraphQL API."

I know about GraphQL but couldn't find any info at all on its use in Canvas. Has anyone heard anything about this? Thanks!

1 Solution

Accepted Solutions

Hi --

I finally had some time to update our local Canvas instance with the latest code from GitHub and I've spent a little time poking at the graphql API.  First, there's a browser-based graphql console (GraphiQL) that is installed along with Canvas, but seems to only be available to users with administrator privileges on the "Site Admin" account (we have access to this in our locally-hosted development instance of Canvas, but not in our Instructure-hosted instances). The actual graphql API endpoint (/api/graphql) is accessible by regular users in our local instance. 

Here's an example of a query that I managed to get to work, sent as the body of a POST request to /api/graphql:

{"query": "
  {
    allCourses {
      id,
      name,
      courseCode,
      state
    }
  }
"}

That returns a data structure with information about the courses that are on the user's dashboard.  Still trying to figure out how to drill down into sections, etc...

--Colin

View solution in original post

16 Replies
nardell
Community Member

Thanks for getting would out that Instructure may be taking steps toward supporting a GraphQL api. I had heard about GraphQL in a talk by David Nolan, and I recognized that it could be a benefit for some of the complex queries we need to do that span over multiple endpoints. Like you I would like to find out more about how Canvas is implementing it.

MIke

phanley
Community Member

Funny coincidence - I just asked our CSR about that last week - I'll update if she's able to get any info. 

phanley
Community Member

BTW, you can get some clues regarding how they're using graphql here: Search · org:instructure graphql · GitHub 

ColinMurtaugh
Community Member

Hey Daniel! 

I'm also very interested in the GraphQL API -- I've seen a bunch of related GitHub commits and I've been meaning to make some time to experiment with it.  I'm expecting to have to read some source code to figure out how to use it 🙂

 

BTW -- we did learn that there's some (fairly edge-case) bug that causes problems rendering student context cards in unpublished courses and/or with inactive students when the GraphQL feature flag is turned on. It seems that Instructure engineering is aware of it, and I imagine it'll be fixed soon, but we've disabled that flag in production for now. 

If I do get it working, I'll share my notes here!

--Colin

Great, thanks, Colin!

Looking forward to hearing about your experiments.

After reading your post I found the experiment graphql api setting

What happens if you turn it on?

Is it an api that I can use or is it an api that canvas uses internally.

I'm interested in what I imagine is the potential here, but I know so little about the implementation that it's dangerous

Is there any schemer or endpoint documentation?

phanley
Community Member

If anyone noticed that the ability to turn it on disappeared from their beta instance, it looks like it's been turned on for everyone....  and that it'll be in production possibly soon

enable graphql feature flag · instructure/canvas-lms@c35e13f · GitHub 

Test plan:   * make sure graphql is turned on for accounts that previously had     graphql enabled and then disabled   * make sure graphql can't be turned off

Hi --

I finally had some time to update our local Canvas instance with the latest code from GitHub and I've spent a little time poking at the graphql API.  First, there's a browser-based graphql console (GraphiQL) that is installed along with Canvas, but seems to only be available to users with administrator privileges on the "Site Admin" account (we have access to this in our locally-hosted development instance of Canvas, but not in our Instructure-hosted instances). The actual graphql API endpoint (/api/graphql) is accessible by regular users in our local instance. 

Here's an example of a query that I managed to get to work, sent as the body of a POST request to /api/graphql:

{"query": "
  {
    allCourses {
      id,
      name,
      courseCode,
      state
    }
  }
"}

That returns a data structure with information about the courses that are on the user's dashboard.  Still trying to figure out how to drill down into sections, etc...

--Colin

That's really interesting - I had been thinking about graphql as a being an admin tool, i.e. being able to write a generic query for a user's courses or whatever, but it seems like it's limited to retrieving info for the specific user that is authenticated against it (unlike how the rest api will let an admin user query all courses, users, etc)

For people that want to poke with a command line, here's a quick recipe (using bash & jq)

bash is easy enough to get going with - set up an alias (replace `generate~your~token` & `yourCanvasServerName` natch):

gqltoken=[generate~your~token]
instance=https://yourCanvasServerName.instructure.com
alias cgql="curl -H \"Authorization: Bearer $gqltoken\" -X POST $instance/api/graphql -H \"Content-Type: application/json\""‍‍‍‍‍‍
‍‍‍

then here's Colin's example as a one-liner piped to jq for easy readability (note: subbing _id for id will give you the canvas id of the courses)

cgql -d "{\"query\": \"{ allCourses {_id,name,courseCode,state}}\"}"‍‍‍‍‍‍‍‍‍‍ | jq‍‍

you can help your explorations a bit using graphql introspection to get a list of types:

cgql -d "{\"query\": \" { __schema {types{name}}} \"}" | jq '.data.__schema.types | .[] | .name'‍

You can get information on a single course using legacyNode(type:Course,_id: xxx):

{
  legacyNode(type: Course, _id: 20512) {
    ... on Course {
      _id
      name
}}}‍‍‍‍‍‍

Here's how to get some course information:

Enrollments is userConnection > edges > node > fieldnames

{
  legacyNode(type: Course, _id: 20512) {
    ... on Course {
      _id
      name
      usersConnection {
        edges {
          node {
            name
            _id
            email
}}}}}}‍‍‍‍‍‍‍‍‍‍‍‍

or as a one-liner (well, a two-liner so the variable is replaceable)

course_id=20512
cgql -d "{\"query\": \" {legacyNode(type:Course,_id:$course_id){... on Course{_id name usersConnection{edges{node{name _id email}}}}}}  \"}"‍‍

Sections are similar: 

{
  legacyNode(type: Course, _id: 20512) {
    ... on Course {
      _id
      name
      sectionsConnection {
        edges {
          node {
            name
            _id
            createdAt
            updatedAt
}}}}}}‍‍‍‍‍‍‍‍‍‍‍‍‍

or 

course_id=20512
cgql -d "{\"query\": \" {legacyNode(type:Course,_id:$course_id){... on Course{_id name sectionsConnection{edges{node{name _id createdAt updatedAt}}}}}} \"}"‍‍ | jq‍‍

Pretty much all of the xConnection types seem to follow that basic pattern and you can end up getting pretty specific results putting it all together - here's an example that get's a single course via it's course id and get's the current user's permissions, plus the course users with grades and analytics :

{
  legacyNode(type: Course, _id: 20512) {
    ... on Course {
      _id
      name
      permissions {
        become_user: becomeUser
        manage_grades: manageGrades
        send_messages: sendMessages
        view_all_grades: viewAllGrades
        view_analytics: viewAnalytics
      }
      usersConnection {
        edges {
          node {
            name
            email
            analytics: summaryAnalytics(courseId: 20512) {
              page_views: pageViews {
                total
                max
                level
              }
              participations {
                total
                max
                level
              }
              tardiness_breakdown: tardinessBreakdown {
                late
                missing
                on_time: onTime
              }
            }
            enrollments(courseId: 20512) {
              last_activity_at: lastActivityAt
              section {
                name
              }
              grades {
                current_grade: currentGrade
                current_score: currentScore
              }
            }
          }
        }
      }
    }
  }
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Sample Output (side note - I'm am still thrilled when emoji don't break apis):

{
  "data": {
    "legacyNode": {
      "_id": "20512",
      "name": "       Dank Memes and Dark Dreams",
      "permissions": {
        "become_user": true,
        "manage_grades": true,
        "send_messages": true,
        "view_all_grades": true,
        "view_analytics": true
      },
      "usersConnection": {
        "edges": [
          {
            "node": {
              "name": "Test Student",
              "email": null,
              "analytics": {
                "page_views": {
                  "total": 3,
                  "max": 67,
                  "level": 2
                },
                "participations": {
                  "total": 0,
                  "max": 0,
                  "level": 0
                },
                "tardiness_breakdown": {
                  "late": 0,
                  "missing": 0,
                  "on_time": 2
                }
              },
              "enrollments": [
                {
                  "last_activity_at": "2017-05-02T15:14:46-04:00",
                  "section": {
                    "name": "Dank Memes       ⚙♻️  "
                  },
                  "grades": {
                    "current_grade": null,
                    "current_score": 63.5
                  }
                }
              ]
            }
          }
        ]
      }
    }
  }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍