0

I'm creating an Express route that calls the GitHub API with a ?callback=foo pattern added to the endpoint so that it will return the Link headers which I'll need to parse out the Link: header because it contains the link that I'll have to call to get the next page of the response.

The problem is that the response has the expected pattern, but when I try to create a function to tease out the meta and data portions of the function, they turn up undefined.

My code:

app.get('/populate', function(req, res, next) {
        console.log('/populate route hit');
        var token = "<something>";
        var options = {
            url: 'https://api.github.com/users?callback=resp',
            headers: {
                'User-Agent': 'Our-App',
                'Authorization': 'token '+ token 
            }
        };
        api(options) // 'api' is request-promise module, makes http requests
        .then(function(response) {
            console.log(response); // Note 1
            function resp(res) {
                var meta = res.meta;
                var data = res.data;
                console.log('meta ', meta); // Note 2
                console.log('data ', data);
            }
            resp(response);

Note 1: The response looks like:

        /**/resp({"meta":{"X-RateLimit-Limit":"5000","X-RateLimit-Remaining":"4993",
    "X-RateLimit-Reset":"1435297775","X-OAuth-Scopes":"public_repo, user:email",
    "X-Accepted-OAuth-Scopes":"repo","Cache-Control":"private, max-age=60, s-maxage=60",
    "Vary":"Accept, Authorization, Cookie, X-GitHub-OTP",
"ETag":"\"0cbbd180648a54f839a237b0302025db\"",
    "X-GitHub-Media-Type":"github.v3; format=json",
    "Link":[["https://api.github.com/users?callback=resp&since=46",
{"rel":"next"}],["https://api.github.com/users{?since}",
{"rel":"first"}]],"status":200},"data":[{"login":"mojombo","id":1,
        ...etc etc...
        }]})

The response looks like it's been JSON.stringified but when I JSON.parse(response) it returns an error. I don't know how to access the deeply-embedded Link: headers and even the data, which looks like JSON, too.

Note 2 The res.meta and res.data log as undefined.

1 Answer 1

1

The response isn't JSON, it's JSONP. JSONP is a cross-domain mechanism for retrieving data. You don't use XHR (e.g., app.get) to request JSONP, you use a script tag. (Because XHR is limited by the Same Origin Policy; script tags aren't.)

If your call retrieving that data via XHR works, it means cross-domain XHR calls are allowed in your situation (the server supports Cross-Origin Resource Sharing with your page's origin, and the browser supports CORS). You can get JSON instead of JSONP by removing the ?callback=resp in the URL.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you. I used the ?callback=resp because the resulting JSONP shows the Link: header in the meta property, while the JSON without the callback does not. Is there another way to access the response Link header? (Need it to know which paginated URI I need to pass to the API next...)
@zahabba: I don't know the github API, but a quick glance at the data suggests that the since parameter in that Link is just the id of the last user. https://api.github.com/users gives me 46 users, with id values 1 to 46. The equivalent JSONP gives me a Link with since=46. And if I do https://api.github.com/users?since=46, I get users 47-91. So...
They warn in their documentation not to compute the value of the since parameter and use the URL in the Link header. But your method seems to be more sensible and I can return to getting a JSON response without the callback. Thanks again!
@zahabba: The alternative, of course, is to use the JSONP feed. I don't know how you'd add those headers to the request, though, if they're necessary. Presumably Github's documentation would tell you. You "consume" JSONP by creating a global function, and using that function's name as the ?callback=xxxxx value. You append a script tag with the URL, and when the script loads, it calls the function with the data (already parsed).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.