Skip to content
This repository has been archived by the owner on Dec 5, 2018. It is now read-only.

My Data API is sending headers/cookies which I am not able to set on response for async fragments #19

Open
nitinagrawal08 opened this issue Dec 9, 2015 · 1 comment

Comments

@nitinagrawal08
Copy link

I am using Async-fragment to show results from my data API calls. My data api calls gives me data as well some response headers and cookies. I have to set those headers and cookies in my response while passing Promise to async-fragment. While doing so I am getting this error:
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)

It is indicating as if I can't use async-fragments if my data api wants me to keep headers/cookies with my responses.

@patrick-steele-idem
Copy link
Contributor

Hey @nitinagrawal08, unfortunately there is no way to set HTTP headers after rendering to the HTTP response stream has begun since the response headers will be committed as soon as the first byte is written to the HTTP response stream. If you are making async service calls and the response of those calls determines which HTTP headers get set then you have no choice but to delay writing the HTML to the HTTP response stream. If you have other async calls then you can still render the template and make the service calls in parallel, but you need to use the callback-style as shown below:

var template = require('./template.marko');
// ...

module.exports = function(req, res) {
    res.setHeader('Content-Type', 'text/html; charset=utf-8');

    // Start rendering the template immediately
    var renderTemplatePromise = new Promise(function(resolve, reject) {
        template.render({...}, function(err, html) {
            if (err) {
                return reject(err);
            }
            resolve(html);
        });
    });

    makeSomeServiceCall()
        .then(function(someData) {
            // Set any other headers based on the service call
            res.setHeader("foo", "bar");

            // Now wait for the template rendering to complete
            // to end the HTTP response
            return renderTemplatePromise;
        })
        .then(function(html) {
            res.end(html);
        })
        .catch(function(e) {
            // Handle the error
        });    
};

At least you are then rendering the template and making the service call in parallel. You could even pass the promise for the service call to the template to use as a data provider.

On a related note, now that promises have been standardized as part of ES6 (and can easily be polyfilled), it probably make sense to introduce a promise API for template rendering.

Thoughts?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants