RejectedSoftware Forums

Sign up

Outputting JSON

Hi, I just started to use vibe.d

I want to generate some JSON for ajax calls. And first thing I tried was .dt templates. They would be quite good match for it, but I don't know how to set content type to "application/json" for them.

Second approach I took was to try to direct write to response stream. But only method that allows setting content type is writeBody. So I'm forced to generate full JSON string before, and then write it.

I would prefer to use .dt and also being able to directly set content type (by property) and be able to write to OutputStream bodyWriter...

Thank you.

Re: Outputting JSON

On Wed, 08 May 2013 12:23:19 GMT, Michal Minich wrote:

Hi, I just started to use vibe.d

I want to generate some JSON for ajax calls. And first thing I tried was .dt templates. They would be quite good match for it, but I don't know how to set content type to "application/json" for them.

Second approach I took was to try to direct write to response stream. But only method that allows setting content type is writeBody. So I'm forced to generate full JSON string before, and then write it.

I would prefer to use .dt and also being able to directly set content type (by property) and be able to write to OutputStream bodyWriter...

Thank you.

Hi. The Diet templates are really very specific to HTML (or to a lesser extent also XML), so those are not really an option. However, there are two possibilities to output a JSON string without writing it to memory first:

  1. HttpServerResponse.writeJsonBody - you, like me, have probably overlooked this in the documentation because it is erreneously documented as a template
  2. Set the content type manually to "application/json; charset=UTF-8" and then use bodyWriter to write the response

Both methods require to build the full in-memory representation of the JSON object first, though (can be type Json or any type that can be serialized to Json). Another alternative, which I haven't yet gotten around to try, is to use embd or mustache-d, two general purpose alternatives to the Diet template format.

I'll look into why the documentation is broken now...

Re: Outputting JSON

Thank you for fast response, now I see more members in docs and also base classes. The combination of .contentType and .bodyWriter properties works well for me.

I'm quite surprised by the limitation of .dt templates, I was hoping to use them for JSON / plain text and some other formats generation. I guess it would be quite useful.

This attempt to generate JSON in .dt failed

[

  • foreach (b; bs)
    {"key":#{b.id}}
    ]

I would consider this code more elegant than writing string to streams and I would very much liked if .dt would not be limited to html

also it generates text/html content type, even if I explicitly set "application/json" in app code just before rendering template.

Re: Outputting JSON

On Wed, 08 May 2013 15:26:26 GMT, Michal Minich wrote:

Thank you for fast response, now I see more members in docs and also base classes. The combination of .contentType and .bodyWriter properties works well for me.

I'm quite surprised by the limitation of .dt templates, I was hoping to use them for JSON / plain text and some other formats generation. I guess it would be quite useful.

This attempt to generate JSON in .dt failed

[

  • foreach (b; bs)
    {"key":#{b.id}}

]

I would consider this code more elegant than writing string to streams and I would very much liked if .dt would not be limited to html

also it generates text/html content type, even if I explicitly set "application/json" in app code just before rendering template.

I think the closest to what you would need for this is embd (basically the same concept, just completely format agnostic), I would give it a try! The Diet templates are a variation of Jade/Haml and have a lot of features that are very specific to the syntax and structure of HTML. This limits them of course, but also allows them to be much more terse/clean than a generic format. I think both kinds of templates have their place after all.

Re: Outputting JSON

By the way, the following wrapper function can be used to get an interface that is similar to the Diet render!() function:

static import embd;
void renderEmbd(string FILE, ALIASES...)(OutputStream dst)
{

	mixin(vibe.templ.utils.localAliases!(0, ALIASES));

	class Context : embd.Context {
		OutputStream output__;

		mixin(renderer);

		void write(string content, dchar eval_code)
		{
			if (eval_code == '=')
				filterHtmlEscape(output__, content);
			else
				output__.write(content, false);
		}
	}

	scope Context ctx = new Context;
	ctx.output__ = dst;
	ctx.render!(import(FILE), `!=`, `<%`, `%>`)();
}

void renderEmbd(string FILE, ALIASES...)(HTTPServerResponse res, string content_type = "text/html; charset=UTF-8")
{
	res.contentType = content_type;
	renderEmbd!(FILE, ALIASES)(res.bodyWriter);
}

void renderEmbdCompat(string FILE, TYPES_AND_NAMES...)(OutputStream dst, ...)
{
	import core.vararg;
	import std.variant;
	mixin(localAliasesCompat!(0, TYPES_AND_NAMES));

	class Context : embd.Context {
		OutputStream output__;

		mixin(renderer);

		void write(string content, dchar eval_code)
		{
			if (eval_code == '=')
				filterHtmlEscape(output__, content);
			else
				output__.write(content, false);
		}
	}

	scope Context ctx = new Context;
	ctx.output__ = dst;
	ctx.render!(import(FILE), `!=`, `<%`, `%>`)();
}

Example usage:

string caption = "Hello, World!";
//res.renderEmbd!("test.embd", caption, req)();
res.bodyWriter.renderEmbdCompat!("test.embd",
	string, "caption",
	HTTPServerRequest, "req")(caption, req);

The non-compat version may suffer from a memory corruption bug in DMD, so I would avoid it for now. I'll prepare a pull request to see if Nathan is willing to include them.

Re: Outputting JSON

Example "test.embd":

<html>
	<head>
		<title><= caption ></title>
	</head>
	<body>
		<p>
			<% if (req.requestURL == "/") { %>
			Good
			<% } else { %>
			Bad
			<% } %>
		</p>
	</body>
</html>

Re: Outputting JSON

On Wed, 08 May 2013 18:12:31 GMT, Sönke Ludwig wrote:

By the way, the following wrapper function can be used to get an interface that is similar to the Diet render!() function:

Has been merged into embd now, so if "embd": "~master" is added as a dependency, it should just work.

string caption = "Hello, World!";
//res.renderEmbd!("test.embd", caption, req)();
res.bodyWriter.renderEmbdCompat!("test.embd",
	string, "caption",
	HTTPServerRequest, "req")(caption, req);