11

I have started building a web application using the Joomla Framework. It consists of a simple web page which will be displayed in an iFrame along with an API that will be used to update the content with AJAX.

I followed the Getting Started with Composer and Joomla! article and have the Framework App up and running. I have customised the default HTML output to work for my iFrame and have made a start on the API. I used News as a template and created a controller, model, table and view for my API which all works great. I then created a very simple Twig template which returns a JSON representation of my data like this:

{{ items|json_encode|raw }}

So far so good but I get this header returned which will cause problems when using AJAX with jQuery:

Content-Type:text/html; charset=utf-8

I thought it would be a simple case of adding this but no matter where I put it, it doesn't change the header that is returned:

$this->app->setHeader('Content-Type', 'application/json', true);

I know that setHeader is working as if I change the name, I see the new header returned so I assume that it is being overwritten later in the execution.

So my question is, am I going about this the right way? My view extends DefaultHtmlView which feels wrong, should I create a DefaultJsonView? How can I set the correct Content-Type or is there a better approach for returning JSON?

Any help of advice that can be given about the best way to use the Joomla Framework to build an API will be greatly appreciated.

3 Answers 3

6

I finally found what seems to be the "correct" way to do this. Even if I used sendHeaders, the additional Content-Type was being added and that got returned as it was added later.

I followed through the code and AbstractWebApplication.php sets the headers with this line:

// Send the content-type header.
$this->setHeader('Content-Type', $this->mimeType . '; charset=' . $this->charSet);

So I was able to define my own mimeType by using this in my code:

$this->app->mimeType = 'application/json';

Now the correct header gets returned and jQuery understands the output as JSON!

4

Took a little digging but I see the issue

https://github.com/joomla-framework/application/blob/master/src/AbstractWebApplication.php

If you look at the setHeader function it does not actually set the header yet, it only gets it "ready"

So what you need to do is simple

$this->app->setHeader('Content-Type', 'application/json', true)->sendHeaders();

The extra function sendHeaders() can be chained to allow you to set the headers, not just "prepare" them.

With most likely using exit; to prevent any further execution and output the JSON the sendHeaders function is most likely not running.

2
  • Thanks for your suggestion. Unfortunately, even why I used sendHeaders, the Content-Type was still begin overwritten. I tried using exit but then I got no output as the template hadn't rendered. I found a solution which I posted as an answer.
    – Joe P
    Jun 6, 2014 at 11:13
  • Well I will add another solution, just so mine works as well for whoever might need it. If you use exit it should prevent anything more from running and just output it as it is currently. Your answer does seem a lot better though. Jun 6, 2014 at 16:39
1

Here you go (for use in controller methods mapped to by webservices plugin-mediated routes predominantly):

This works in J! 3 & J! 4

In your controller's class, add the following public method (I add as part of a trait but to each their own):

  /**
   * emitJson
   *
   * @author    Joe Hacobian
   * @since v0.0.1
   * @access    public
   * @param mixed   $inputArr
   * @return    void Writes Response & closes connection
   */
  public function emitJson($inputArr)
  {
    /* Thanks go out to Nicholas K. Dionysopoulos from Akeeba
    for coming up with emitting JSON from Joomla this way.
    */
    header('Content-type:application/json;charset=utf-8');
    // Add the following header only if you run into intractable CORS issues.
    // header('Access-Control-Allow-Origin: *');
    @ob_end_clean();
    echo (json_encode($inputArr));
    flush();
    $this->app->close();
    return;
  }

Joomla 'catches' the echo'd output, thus it's necessary to stop output buffering during the json response emission, then echo the encoded json, and then to call flush() in order to make sure the output is sent.

Since this is a REST API response, it follows that JSON response emission is the final act in the lifecycle of a REST endpoint, this is why we call:
$this->app->close();

This means that the return; statement is never executed, it is included as a semantic device only.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.