@jbeast
There could be several things causing the problem.
The thing that first jumps out is that it looks like dev.iheed.org is a test or beta instance of Canvas. From your main website, it takes you to learn.iheed.org as the production instance of Canvas. Beta and test are always going to be slower than production. Sometimes they are faster than others, but rarely is beta slower than production (unless production is having issues or network congestion). That alone could be an explanation of why it's slower here than on another system with the same content.
I just tested the same course in beta and production. It took 1.234 s in beta, 0.856 in test, and 0.544 s in production to load. Those numbers vary, of course, and re-executing the GET statement will return different times. It does not appear that refreshes are automatically quicker, though. In some areas, Canvas has a cache that gets loaded and then used when you fetch the same content. Then I tried it in a course that had a lot of modules and it took 0.892 s for production, 1.517 s for beta, and 1.650 for test.
None of that was fetching module items, it was just asking for a list of the modules. When I request the module items, the first course took 1.343 s in beta, 1.297 s in test, and 0.976 s in production. The second course took 1.226 s in production, 1.883 s in beta, and 1.723 s in test.
There may be more going on than just that.
I noticed you had per_page=500 on your first request. In general, Canvas doesn't support more than 100 at a time. You can verify this by looking at the link header in the response. When I try per_page=500, it comes back with links that contain per_page=100. Some programmers have chosen "what does it matter? The sky is the limit. I'll just ask for the moon and accept a two-story building if that is all that Canvas will give me."
However, in my experience, reducing the number allowed speeds the process up, even if the limit is never reached. I cannot seem to duplicate that behavior here, but I have seen it in other places. One of those is when I download information for each student every night for our early-alert system. The enrollments API seems particularly costly. The x-request-cost for something with 100 (or 500) per_page is higher than if I'm requesting 20 or 50 items. When making multiple asynchronous requests, you are more likely to use up the x-rate-limit-remaining that starts at 700 if you request larger per_page values.
While I see that most requests complete faster, the downside is that you might have to make more requests. I pick a medium value that I'm happy with to minimize that. I mean, do most courses really have 100 modules in them? Remember that per_page on the modules request applies to the number of modules, not the number of module items. My first course only had 10 modules and my second course had 65 modules.
I pulled up our Canvas Data and did a query to see how many modules were being used per course. I know that we're a small institution, with only 8274 courses in this query, and your course design will likely differ from ours, but here's what I found. The default per_page is 10, but only 44.95% of our courses had 10 or fewer modules. 92.40% of our courses had 20 or fewer items. 95.13% had 22 or fewer items. 98.30% had 30 or fewer items, 99.07% had 35 or fewer items. 99.50% had 40 or fewer items. 99.88% had 50 or fewer items. The most that any course had was 80 module items.
You may be able to speed things up by specifying a lower per_page setting. Specifying 500 accomplishes nothing because the max it will take is 100.
Loading module items is only necessary if Canvas does not return them with your modules. If you have a lot of module items in a module, then it may not return them. I mention this not because of the speed issue, but just to make sure you're not blindly downloading information you already obtained. Reducing the per_page for the module request may increase the likelihood of getting all of the module items. I don't have any evidence to back that up, but for those modules where the items weren't returned, you may want to try lowering the per_page and see if then gives you the items.
Depending on what you need, you may be able to use the GraphQL interface to fetch your information. It only returns the information that you request, rather than a bunch of information you don't need, and can be quicker. Unlike many of the GraphQL endpoints, the one for modules only returns those that are active (others return all and you have to manually filter on the status). One of the courses I queried with Canvas Data had 97 modules, but only 16 were active. The GraphQL only returns the 16, which is good.
It is likely that you would be able to fetch all of the module information much faster, as well. Getting just a list of the modules with their id, name, and position took 0.105 s my course with 65 modules (this is on production). That took 0.892 s through the modules API.
That doesn't contain any of the module information, though. That module information is a little trickier to get as you have to specify what you want for each type of module item. You cannot even get a name for every module item, you have to go into the content type and specify what you want. Classic Quizzes aren't really supported well (I would get the information for quizzes from the assignments type). The speed-up may be there if you need the module items. I asked it for just the ID and name/title for each of the items and it took 0.919 s. Compare that to 1.226 s previously and it could easily be a difference due to network traffic. The modules?include[]=items is a lot simpler and probably gives you all that you need.
There are other possibilities. I experience more delay when loading my content than other people do. I had Instructure look at it back in April 2017 and when they viewed my courses as them, it was quick. When they viewed it as me, it was slow. The more modules and the more items in the modules, the longer it takes to load. I've seen 6+ seconds in production for some of my courses until I went through and optimized my content. I don't think that's what is going on with you. The most likely culprit, based off what you've given us, is the Canvas instance you're pulling the information from.