Celebrate Excellence in Education: Nominate Outstanding Educators by April 15!
Found this content helpful? Log in or sign up to leave a like!
Dear all,
In my tool I need to query the course for sections, using the Canvas API (specifically, the endpoint /api/v1/courses/<course_id>/sections?include[]=students&include[]=total_students)
All seems to be fine and I get the expected result. Though I'm unsure about something:
The list of students returned by the call doesn't include an "email" field. Instead, I get a "login_id" field that is actually the student email... Is this always the case? or is it possible to have a student with a "login_id" other than the email address? And if this is the case, how then can I get the email address of the student when querying the course sections?
What I need here, in short, is a way to map the students returned by the Canvas API with the learners information provided by the LTI protocol when a launch request is issued and the student email seems to be the only information I can use to uniquely identtify the Canvas API student with the corresponding user provided by the LTI launch.
So: is the login_id always representing the student email?
Thanks in advance!
Solved! Go to Solution.
@Davidemolin try this call and see if it works for you:
/api/v1/courses/<course_id>/sections?include[]=students&include[]=email&per_page=100
The login_id is the initial login credential that uniquely identifies a user profile. While it is typically the student's email address, it can also be another unique identifier in some cases.
You can retrieve the student email by sending a GET request to the /api/v1/users/:user_id/profile
endpoint. If you prefer to get this information in a single request, you can use GraphQL with the following query:
query MyQuery {
course(id: "course_id") {
sectionsConnection {
nodes {
students {
nodes {
email
name
}
}
}
}
}
}
Thanks for the hint @jerry_nguyen , I'll give that a try.
Though, one question: if I query the course sections through GraphQL instead of the REST API, do things like pagination limits still apply (this happens with the sections API call) ? if I've a course with 1000 students divided into 100 sections, is the query giving me all the results in one single call? or do I have to worry about the result being potentially "paginated"?
Do you know if GraphQL queries work with scoped access? I'm very concerned that this does not work at all if scoped tokens are configured in Canvas (as is my case).
I tried running my query against the GraphQL endpoint but I keep getting "Insufficient scopes on access token" (my current allowed scopes are "url:GET|/api/v1/courses/:course_id/sections" and "url:GET|/api/v1/users/:user_id/profile")
I found something similar documented here but it looks like there was never a follow up to that issue: https://community.canvaslms.com/t5/Canvas-Question-Forum/Scoped-token-does-not-work-with-GraphQL/m-p...
Is there any form of support you or someone else at Instructure can give me on this? As far as I can see the GraphQL API doesn't work where access tokens use enforced scope (that is something the vast majority of serious Canvas admins do) so that makes the entire GraphQL API a bit pointless, and it's a bit disappointing to see that issues were reported back in 2021 on this with Instructure providing absolutely zero feedback on this (https://github.com/instructure/canvas-lms/issues/1891).
Not having the possibility of getting learners emails through the Canvas REST API is a major omission and roadblock right now since we're not able to match the resulting students with the profiles data we receive through LTI Advantage. That would've been the only way for us to support Canvas "sections" (since they're not part of the LTI specification and as such we have to go through the Canvas REST API).
Any form of support on how to make the GraphQL API work with access tokens with enforced scope would be majorly appreciated!
Are you able to provide more context as to what you are trying to accomplish with your LTI that requires the use of the Canvas API? This will help with more accurate suggestions for an improved workflow that may not require access to the API or may only need the Names and Roles API access for user provisioning depending on what you are trying to accomplish. There are also variable substitutions that can be configured for an LTI to provide some additional Canvas specific information when an LTI is launched. Some of the available options include data on Canvas sections, which may provide the information you need without the use of the API.
Nonetheless, while @jerry_nguyen did show an example with GraphQl, he also provided the REST API endpoint you can use to get a user's profile that will include their primary email address. This doesn't require the use of GraphQL and can be accessed with a scoped access token. Based on the restrictions you mentioned, your token should have access to this endpoint. However, it is important to keep in mind that the primary email address could potentially change for a user and it would be useful to include a disclaimer for this and also a planned work-around if a user's primary email address does change such as when they have a name change.
Thanks for chiming in, it's really appreciated.
We would be very happy not to use the Canvas REST API in the first place and only stick to LTI but that seems not to be possible. In our tool we want to be able to capture the "sections" present in a Canvas course, along with the students included in each section; Course "Sections" are something that is not part of any LTI specification and as such we were forced to use the Canvas REST API to capture this information. The same holds true for the sections composition (that is, the students that are associated with each section in the course).
The main problem here is that when we query Canvas to retrieve the course sections and their members we don't get a complete "picture" of the students, since their email is missing from the list. I would also be happy to avoid using the email as a unique identifier for the students in this particular flow but here we're hitting another roadblock: The list of students we get from Canvas via the REST API and the list of students we get from LTI Advantage (Names and Roles) are hard to reconcile... LTI Advantage gives us a list of learners with "user_id" that have meaning only inside LTI, while when we query Canvas (via its REST API) we get list of students with "id" that are meaningful inside of that Canvas LMS but (for obvious reasons) don't match the LTI counterparts... So, in order to "combine" these 2 pieces of information from the course, we need to find a way to recognize which course "section" student correspond to the LTI course student that we retrieved via LTI Advantage, and the email seems to be the only element we can use atm.
LTI remains the main and first level of communication for our tool (while we add additional intelligence to it when interfacing with a Canvas LMS, like identifying course sections and their members) so we end up querying both ways.
using endpoints like /api/v1/users/:user_id/profile
is definitely out of question: most often I'm fetching 100+ students from the course sections API call; I cannot issue 100+ GET requests just to get each student's email, that would be massively inefficient.
If you have suggestions on how to bridge this gap between the two worlds (Canvas and LTI) so we can more easily do our matching without resorting to email addresses I'd be more than happy to hear.
Our strategy, at the moment, is still sound though: When we import/sync the course learners into our tool we query LTI Advantage first (this allows us to "create" user accounts on our system that correspond to the LTI course students); This is followed by a call to Canvas REST API; as we do so we match the Canvas students with their corresponding LTI counterparts and we store the Canvas student "id" (as returned by the Canvas REST API) in the account we created (from the original LTI response), so the next time we need to sync with the LMS (useful in case more students have been added to the LMS course) we can match the results of the Canvas REST API call directly by Canvas user Id without relying on the student email; this ensure we're safe in the eventuality of a student updating the email address.
Moreover, @agschmid below provided a fantastic tip! it seems that `include[]=email` actually provides us with the email of the students! This parameter is not documented in the Canvas REST API documentation; is it safe to use? or is it something that might be removed with no notice at some point in time?
Have you tried using any of the variable substitutions as additional custom fields that are included in the LTI launch? I'm not sure if this information would also be included when you perform a sync using LTI Advantage (Names and Roles), but this information is included when a user launches the LTI. There are several options to get information about sections when the LTI is launched from a course, without the need for an additional API call.
As for the undocumented request parameter, they are always a "use at your own risk" type of option. Since it is undocumented there is potential for it to be removed at any time without any warning. While this may not happen, it is up to you to decide if it is worth the risk.
If the variable substitutions don't provide the section data with the LTI Advantage and performing a full roster sync is essential rather than provisioning users as they launch the LTI, then there are other API endpoints that could be used. The List Users in a Course endpoint retrieves the users within a course and it includes the primary email address for the users. It also has the option to include enrollments, which can provide information on the section(s) each user is enrolled in.
Thanks again for your insight. Yes, I've tried; I already use variable substitutions (and they are very valuable!) but there's no way to get information on a course sections+users during an LTI launch with custom variables only (as an example, the "$com.instructure.User.sectionNames" just gives me the name of the course sections the instructor is part of).
Isn't it possible to officially ask Instructure to "add" the email parameter in the sections API call supported params documentation instead of considering it an "undocumented" feature? It's already there and its usefulness is undeniable. I can take a look at the "List Users in a Course" API endpoint too, sure, but it seems a waste of bandwidth to me since its output is much more verbose than what I get with the sections API call.
@Davidemolin try this call and see if it works for you:
/api/v1/courses/<course_id>/sections?include[]=students&include[]=email&per_page=100
Ohhh! this is amazing @agschmid ! it works! is this an undocumented feature? do you think it's safe to use or could this be something that is not officially supported and might be removed from the API at any time?
I've found several undocumented features and in the past (especially if I found it in their code) I would ask if this is going to continue to be supported. Usually, the answer is that they missed documenting something. I've been using this for reports I create and it has worked well, but you could always create a ticket and ask them if this was an oversight that it's not documented and if it's going to go away.
To participate in the Instructure Community, you need to sign up or log in:
Sign In