Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Force JSON output regardless of URL extension #1067

Closed
Perlkonig opened this issue Sep 24, 2016 · 9 comments
Closed

Feature request: Force JSON output regardless of URL extension #1067

Perlkonig opened this issue Sep 24, 2016 · 9 comments
Assignees

Comments

@Perlkonig
Copy link
Contributor

I have a plugin that returns a status reports. It should always be JSON (using the *.json.twig template). I don't want to force the client to append .json to the URL. I just want to programmatically trigger the response as JSON. It's currently not possible to do this.

@w00fz
Copy link
Member

w00fz commented Sep 30, 2016

This is kind of the pattern we follow though. I think it would be somewhat confusing and inconsistent if suddenly you could return different output formats from different extensions. .json could now suddenly return HTML, .html could now suddenly return RSS/XML. etc.

Have you considered forcing a redirect for your html route to the .json version of it? This way even if the client reaches the regular route, it will still automatically get redirected to the json version of it.

@rhukster
Copy link
Member

I'm ok with adding support for this @w00fz but it will probably not be something in admin. It's a very advanced feature that is not going to be used often.

@Perlkonig
Copy link
Contributor Author

Perlkonig commented Sep 30, 2016

I'm thinking from a web service perspective. URLs are supposed to be opaque. One URL represents one resource, which can have multiple representations. The client is supposed to be able to send an Accept header that tells the server what representation they want (e.g., text/html, application/json, etc.). The URL represents the resource itself and shouldn't change.

So with the Webmention plugin, when you submit a mention, you can optionally be given a URL to check later for the status of your request. If the client is a person, they may want an HTML response. They'd just check it from their browser (automatically a text/html request) and get something formatted and pretty. If the status check is done by a script, it would prefer application/json. It signals that in the Accept header. It shouldn't have to change the URL to get that output.

As it stands, I am not aware of a method for me to, from a plugin, force a response in a specific MIME type. I can change it's template, but I can't force Grav to use the *.json.twig over the *.html.twig from within the plugin. I admit this may not be a common need, but it is conformant with HTTP best practices.

And yes, URL opaqueness aside, you should certainly refrain from returning JSON output if the URL ends with .html. That's confusing. But all my Grav URLs are extensionless. It's just stuff like /blog/test.

And while it would be great if Grav just did this automatically (maybe a system.yaml flag that turned off and on Accept header service), I'm not saying you should. I'd be content with a facility to do that on a page-by-page basis. Thanks again for your time!

@rhukster rhukster self-assigned this Sep 30, 2016
@w00fz
Copy link
Member

w00fz commented Sep 30, 2016

Ok I can see some valid points here and I can see a couple things we could improve this, imo.

I think that, and I am not too sure about this as I need to double check the code, we implicitly assume a direct hit to a route is HTML and that it looks for the .html.twig template for it, not there fails or defaults to default.html.twig, based on the page type.

Probably this should be smarter behind the scenes and Grav should be able to automatically determine that if a .html.twig is not present but a .json.twig is, then it should use that. If there is also a .rss.twig then it should use the one with the most priority, priority that we arbitrary decide as makes the most sense (this could even be a config option). HTML > JSON > RSS > ETC.
It would be nice if at the page level we could also set the default extension, rather than implicitly assume html. That way if we have both .html.twig and .json.twig and a page says the default extension is .json, hitting the route would return JSON, but hitting the route.html would return HTML.

The second aspect that we could improve is what you suggest in regards of headers. I can see now your point and I agree that requesting with application/json should coerce the route to use the json template, even if an HTML is present.

Is this what you had in mind also @rhukster ? Also how does this sound to you @Perlkonig ?

@Perlkonig
Copy link
Contributor Author

If you're looking at an ideal long-term solution, then I recommend the following (I haven't dug through the source code yet).

  • When the system is ready to generate output, it should look at the Accept header (https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html).
  • It then goes through the Accept MIME types in preference order. (You'd need some sort of map between MIME types and template.*.twig codes.)
  • The first MIME type that matches an existing template, bingo. You run the content through the template, generate the headers (including Content-Type), and respond.
  • If no matches are found, the correct response is 406 Not Acceptable.

This would remove all responsibility from the content creators. They'd just need to make sure the templates are there or are conspicuously absent. The rest is up to the agent.

A page-level override also seems cheap to implement and would be useful both as a stop gap and also as an override once the high-level changes are made.

I recognize this is a pretty major change, but I think it would be a very positive one.

@rhukster
Copy link
Member

My idea was to at least add the page-level override. But that Accept header option sounds like a good idea too.

rhukster added a commit that referenced this issue Sep 30, 2016
@rhukster
Copy link
Member

rhukster commented Sep 30, 2016

Ok, added this and implemented Sitemap using this functionality: getgrav/grav-plugin-sitemap@00c2373

Page-level override only at this point.

@rhukster rhukster added the fixed label Sep 30, 2016
@Perlkonig
Copy link
Contributor Author

You 'da man.

@Perlkonig
Copy link
Contributor Author

Proof of concept in PR #1088

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

No branches or pull requests

3 participants