Is there a standard syntax for encoding structure objects as parameters for an HTTP GET request?
Suppose we need to pass several structured objects to a web application - for example, locale, layout settings, and some query definition. This can be easily done with JSON or XML similar to the following snippet:
<Locale>en</Locale>
<Layout>
<Block id="header">hide</Block>
<Block id="footer">hide</Block>
<Block id="navigation">minimize</Block>
</Layout>
<Query>
<What>water</What>
<When>
<Start>2010-01-01</Start>
</When>
</Query>
However, transferring such structures with HTTP implies (roughly speaking) HTTP POST.
Now let's say we are limited to HTTP GET. Is there some standard solution for encoding structured data in HTTP GET request parameters?
I can easily imagine something like:
Locale=en&
Layout.Block.header=hide&
Layout.Block.footer=hide&
Layout.Block.navigation=minimize&
Query.What=water&
Query.When.Start=2010-01-01
But what I'm looking for is the "standard" syntax, if any.
ps. I'm pretty sure the problem is with the url length. Let's assume this is not a problem in this case.
PPS. I would also be helpful for links to key value pairing APIs (like Paypal NVP ) that you think are worth taking a look at.
PPP. We are looking at the callback urls of course, but we also need the HTTP GET key-value pairs. The question focuses on the latter.
a source to share
As far as I know, there are no standards for transferring structured data using GET. There are several conventions (the PHP / RoR example above is probably the most common), but nothing that has reached any level of maturity, documentation, reference implementation, etc. is considered standard.
And this is not too surprising, a simple standard did not appear. There are open-ended questions, the answers to which depend on the specifics of the situation. Where the url needs to be transparent (like visible request parameters) or opaque (like base64 encoded). Can compression be used? Can / should / should use / support other views, eg. JSON, binary XML, or even Google protocol buffers ). How is URL overflow handled? 10 different people can give different answers about what is needed based on their situation. The standard can try to solve all these problems, but then it will be far from easy.
Even if there was a standard, would it be wise to follow it?
It is advisable, reassuring even to follow the standard, knowing that your work is built on the road proven work of respected field experts and engineers, and knowing that we are being invited to a party and playing with other systems that follow the same standard. But when the requirements are as diverse as they are here, the standard will usually give you a middle group solution, a means of unification. And when you're only 2K to play, the inclusion will probably be the last on your list!
Roll your own and you are sure to get exactly what you want. I would like to represent as binary XML files or protocol buffers, gzipped and base64, but you can resize.
Anyway, good luck!
a source to share
Well, the standard way to encode data into a URI is application/x-www-form-urlencoded
. The way most applications handle hierarchical data is enclosed in square brackets in the key part. For instance:.
Locale=en&
Layout[Block][header]=hide&
Layout[Block][footer]=hide&
Layout[Block][navigation]=minimize&
Query[What]=water&
Query[When][Start]=2010-01-01
This is a somewhat specific application, but it is quite close to the de facto standard.
a source to share
It depends on how you want to decode it. Your solution works if you have a system that knows how to separate parameters and values by &
and =
(that is, PHP), but if this limitation is removed then it can become much more concise:
Locale{en}Layout{Block(id:header){hide}Block(id:footer){hide}Block(id:navigation){minimize}}Query{What{water}When{Start{2010-01-01}}}
In short, there is no standard (as far as I can find), so be creative according to your needs. You can even use JSON, omitting or encoding spaces as needed.
a source to share
This idea will only work if you have control on both the server and client and both are mutually accessible over the network.
Client-end:
The client calling the server will have to pass the callback url in the HTTP-HEADER HTTP-REQUEST. The URL will also have a unique ID and the REQUEST sample might look like this.
//HTTP Request Header
GET / HTTP/1.1[CRLF]
Host: www.your-server.com/server-end.aspx[CRLF]
Connection: close[CRLF]
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.2; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)[CRLF]
Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7[CRLF]
Cache-Control: no[CRLF]
Accept-Language: de,en;q=0.7,en-us;q=0.3[CRLF]
Referer: some referrer[CRLF]
Input-callback-Url: www.your-client.com/inputprovider.aspx?requestid=xxxxxxx[CRLF]
[CRLF]
Server end:
At the server endpoint, the server will read the Http request headers from the client and read the url received in "Input-callback-Url". The server will then run an Http-Request GET at www.your-client.com/inputprovider.aspx?requestid=xxxxxxx. This URL, when called to the server, outputs the result in JASON or XML form.
<Locale>en</Locale>
<Layout>
<Block id="header">hide</Block>
<Block id="footer">hide</Block>
<Block id="navigation">minimize</Block>
</Layout>
<Query>
<What>water</What>
<When>
<Start>2010-01-01</Start>
</When>
</Query>
The server can receive this response from the "Input-callback-Url" and continue with the original client request.
a source to share
I understand that you are very good at understanding. I have loved and used XML and XML Schema for many years. For half a year I've been using JavaScript and jQuery along with RESTfull WFC services, ASP.NET MVC technologies with JSON encoded data for transmission. So I should have asked me the same question a while ago. Here is my answer with a short explanation.
The XML structure that you define can represent one input parameter to our web service. If you prefer to split your XML structure into different props (such as Locale, Layout and Query), everything I write here can be easily changed in this case of parameter coding.
The most natural way, in my opinion, is the way we implement using off-the-shelf tools . So let's have our web service with a type method MyMethod
and an input parameter of param
1 with a type MyData
(something like public int MyMethod (MyData param1)
). The class MyData
represents our data from an XML structure. Then the corresponding HTTP GET request should look like
http: // server / Service / MyMethod? param1 = JsonEncodedData
where JsonEncodedData strong>:
% 7B% 22locale% 22% 3A% 22en% 22% 2C% 22layout% 22% 3A% 5B% 7B% 22id% 22% 3A% 22header% 22% 2C% 22value% 22% 3A% 22hide% 22% 7D% 2C % 7B% 22id% 22% 3A% 22footer% 22% 2C% 22value% 22% 3A% 22hide% 22% 7D% 2C% 7B% 22id% 22% 3A% 22navigation% 22% 2C% 22value%
or without HTML encoding:
{"locale": "an", "location": [{"ID": "title", "value": "skin"}, {"ID": "footer", "value": "hide"}, {"ID": "navigation", "value": "minimize"}], "query": {"what": "water", "when": {"Start": {"Year": 2010, "month ": 1," Day ": 1}}}
This data is JSON encoded JavaScript objects.
var myInput = {
locale: "en",
layout:[
{id: "header", value: "hide"},
{id: "footer", value: "hide"},
{id: "navigation", value: "minimize"}
],
query:{
what: "water",
when: {
Start:{Year:2010,Month:1,Day:1}
}
}
};
NOTE . Since the JavaScript class Date
can be serialized in a number of ways, I slightly changed the start date representation. In the "Microsoft world" we can use Sys.Serialization.JavaScriptSerializer.serialize
to serialize a DateTime
.NET type that will encode 2010-01-01, for example "/ Date (1262300400000) /".
We can write in C # a simple web method Web Service Service1.asmx like
[WebMethod]
[ScriptMethod (UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public int MyMethod (MyData param1) {
return param1.query.when.Start.Year;
}
Where
public enum BlockType {
hide,
minimize
}
public class Block {
public string id { get; set; }
//public BlockType value { get; set; }
public string value { get; set; }
}
public class MyDate {
public int Year { get; set; }
public int Month { get; set; }
public int Day { get; set; }
}
public class When {
public MyDate Start { get; set; }
}
public class Query {
public string what { get; set; }
public When when { get; set; }
}
public class MyData {
public string locale;
public List<Block> layout;
public Query query;
}
And the corresponding client code would look like this
var myInput = {
locale: "en",
layout:[
{id: "header", value: "hide"},
{id: "footer", value: "hide"},
{id: "navigation", value: "minimize"}
],
query:{
what: "water",
when: {
Start:{Year:2010,Month:1,Day:1}
}
}
};
$.ajax({
type: "GET",
url: "/Service1.asmx/Method2",
data: {param1: JSON.stringify(myInput)},
contentType: "application/json; charset=utf-8",
success: function(data, textStatus, XMLHttpRequest) {
alert(XMLHttpRequest.responseText);
},
error: function(res, status) {
if (status ==="error") {
// errorMessage can be an object with 3 string properties:
// ExceptionType, Message and StackTrace
var errorMessage = $.parseJSON(res.responseText);
alert(errorMessage.Message);
}
}
});
For JSON encoding, I am using json2.js in the example (see https://github.com/douglascrockford/JSON-js/blob/master/json2.js and http://www.json.org/js.html ) ... JSON jQuery (from http://code.google.com/p/jquery-json/ ) can be used instead , then JSON.stringify
should be replaced with $.toJSON
.
The data initialization of the type MyData
might look like
new MyData {
locale = "en",
layout = new List<Block> {
new Block() { id="header", value=BlockType.hide.ToString()},
new Block() { id="footer", value=BlockType.hide.ToString()},
new Block() { id="navigation", value=BlockType.minimize.ToString()}
},
query = new Query {
what = "water",
//when = new When() {Start = new DateTime(2010,1,1)}
when = new When () {
Start = new MyDate () {
Year = 2010,
Month = 1,
Day = 1
}
}
}
};
}
If you are using WCF with webHttpBinding (RESTfull endpoints) instead of asmx based web services, you can get a more flexible solution.
If the use is using JSON with HTTP GET, you should take into account the existence of a JSON Hijacking problem (see http://weblogs.asp.net/scottgu/archive/2007/04/04/json-hijacking-and-how-asp- net-ajax-1-0-mitigates-these-attacks.aspx , http://haacked.com/archive/2009/06/25/json-hijacking.aspx ). This problem can be solved (or drastically reduced) in different ways, and that doesn't stop me from using JSON in HTTP requests, which can be ideally cached.
For more information on the same subject, you can view my answer to related questions: How do I create a JSON object to send to an AJAX WebService? Is it possible to return JSON from .asmx webservice if ContentType is not JSON? JQuery ajax call httpget webmethod (C #) not working
a source to share