How to Serialize an Object into a List of Url Query Parameters

How to serialize an Object into a list of URL query parameters?

var str = "";
for (var key in obj) {
if (str != "") {
str += "&";
}
str += key + "=" + encodeURIComponent(obj[key]);
}

Example: http://jsfiddle.net/WFPen/

How do I serialize an object into query-string format?

I'm 99% sure there's no built-in utility method for this. It's not a very common task, since a web server doesn't typically respond with a URLEncoded key/value string.

How do you feel about mixing reflection and LINQ? This works:

var foo = new EditListItemActionModel() {
Id = 1,
State = 26,
Prefix = "f",
Index = "oo",
ParentID = null
};

var properties = from p in foo.GetType().GetProperties()
where p.GetValue(foo, null) != null
select p.Name + "=" + HttpUtility.UrlEncode(p.GetValue(foo, null).ToString());

// queryString will be set to "Id=1&State=26&Prefix=f&Index=oo"
string queryString = String.Join("&", properties.ToArray());

Update:

To write a method that returns the QueryString representation of any 1-deep object, you could do this:

public string GetQueryString(object obj) {
var properties = from p in obj.GetType().GetProperties()
where p.GetValue(obj, null) != null
select p.Name + "=" + HttpUtility.UrlEncode(p.GetValue(obj, null).ToString());

return String.Join("&", properties.ToArray());
}

// Usage:
string queryString = GetQueryString(foo);

You could also make it an extension method without much additional work

public static class ExtensionMethods {
public static string GetQueryString(this object obj) {
var properties = from p in obj.GetType().GetProperties()
where p.GetValue(obj, null) != null
select p.Name + "=" + HttpUtility.UrlEncode(p.GetValue(obj, null).ToString());

return String.Join("&", properties.ToArray());
}
}

// Usage:
string queryString = foo.GetQueryString();

How do I serialize an object that has a list of objects as a parameter into query-string format?

I would use Newtonsoft.Json and HTTP POST (with JSON content-body) to send nested objects such as this because there is no standard way to represent lists of objects using query-string parameters

If GET is your only option, you could try something like this:

Uri.EscapeDataString(JsonConvert.SerializeObject(criteria))

Converting it back to an object at the other end would be the reverse of this

JsonConvert.DeserializeObject(Uri.UnescapeDataString(queryString))

Query-string encoding of a JavaScript object

Like this:

serialize = function(obj) {
var str = [];
for (var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
}

console.log(serialize({
foo: "hi there",
bar: "100%"
}));
// foo=hi%20there&bar=100%25

Serialize object of params to url

const params = {
id: 1,
filters: {
price: {
min: 101,
max: 300
}
},
sorters: {
sortBy: 'price',
order: 'desc'
}
}

function add(a, o) {
for (const [key, value] of Object.entries(o)) {
if (typeof value === 'object') add(a, value); // recursion
else a.push(`${key}=${value}`); // only if value not-an-object
}
return a;
}

console.log(add([], params).join("&"))

How to convert URL parameters to a JavaScript object?

In the year 2021... Please consider this obsolete.

Edit

This edit improves and explains the answer based on the comments.

var search = location.search.substring(1);
JSON.parse('{"' + decodeURI(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g,'":"') + '"}')

Example

Parse abc=foo&def=%5Basf%5D&xyz=5 in five steps:

  • decodeURI: abc=foo&def=[asf]&xyz=5
  • Escape quotes: same, as there are no quotes
  • Replace &: abc=foo","def=[asf]","xyz=5
  • Replace =: abc":"foo","def":"[asf]","xyz":"5
  • Suround with curlies and quotes: {"abc":"foo","def":"[asf]","xyz":"5"}

which is legal JSON.

An improved solution allows for more characters in the search string. It uses a reviver function for URI decoding:

var search = location.search.substring(1);
JSON.parse('{"' + search.replace(/&/g, '","').replace(/=/g,'":"') + '"}', function(key, value) { return key===""?value:decodeURIComponent(value) })

Example

search = "abc=foo&def=%5Basf%5D&xyz=5&foo=b%3Dar";

gives

Object {abc: "foo", def: "[asf]", xyz: "5", foo: "b=ar"}

Original answer

A one-liner:

JSON.parse('{"' + decodeURI("abc=foo&def=%5Basf%5D&xyz=5".replace(/&/g, "\",\"").replace(/=/g,"\":\"")) + '"}')

Converting a POCO object with JsonPropertyName decorations into a URL query string

To my knowledge there is no native .NET API, it seems like ASP.NET (Core) has support for reading it to some extent though (check here and here) but I can't tell how to create one.

The laziest solution would probably be to just serialize your object to JSON, and then HttpUtility.UrlEncode(json), then pass that to a query param, which would like so:

&payload=%7B%22response_type%22%3A%20%22code%22%2C%22client_id%22%3A%20%22a%3Ab%22%7D

At the other end just JsonSerializer.Deserialize<AuthEndPointArgs>(HttpUtility.UrlDecode(payload)) like so. This is assuming you can edit both ends.

While it sounds kinda stupid, it works, at in certain terms may even be better than serializing your AuthEndPointArgs to a query string directly, because the standard for a query string lacks some definitions, like how to deal with arrays, also complex options. It seems like the JS and PHP community have unofficial standards, but they require a manual implementation on both ends. So we'll also need to roll our own "standard" and implementation, unless we say that we can only serialize an object that fulfils the following criteria:

  • No complex objects as properties
  • No lists/ arrays as properties

Side note: URLs have a maximum length depending on a lot of factors, and by sending complex objects via query parameters you may go above that limit pretty fast, see here for more on this topic. It may just be best to hardcode something like ToQueryParams like Ady suggested in their answer

If we do want a generic implementation that aligns with those criteria, our implementation is actually quite simple:

public static class QueryStringSerializer
{
public static string Serialize(object source)
{
var props = source.GetType().GetProperties(
BindingFlags.Instance | BindingFlags.Public
);

var output = new StringBuilder();

foreach (var prop in props)
{
// You might want to extend this check, things like 'Guid'
// serialize nicely to a query string but aren't primitive types
if (prop.PropertyType.IsPrimitive || prop.PropertyType == typeof(string))
{
var value = prop.GetValue(source);
if (value is null)
continue;

output.Append($"{GetNameFromMember(prop)}={HttpUtility.UrlEncode(value.ToString())}");
}
else
throw new NotSupportedException();
}
}
}

private static string GetNameFromMember(MemberInfo prop)
{
string propName;

// You could also implement a 'QueryStringPropertyNameAttribute'
// if you want to be able to override the name given, for this you can basically copy the JSON attribute
// https://github.com/dotnet/runtime/blob/main/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonPropertyNameAttribute.cs
if (Attribute.IsDefined(prop, typeof(JsonPropertyNameAttribute)))
{
var attribute = Attribute.GetCustomAttribute(prop, typeof(JsonPropertyNameAttribute)) as JsonPropertyNameAttribute;
// This check is technically unnecessary, but VS wouldn't shut up
if (attribute is null)
propName = prop.Name;
else
propName = attribute.Name;
}
else
propName = prop.Name;

return propName;
}

If we want to support objects with enumerables as properties or with "complex" objects as members we need to define how to serialize them, something like

class Foo
{
public int[] Numbers { get; set; }
}

Could be serialized to

?numbers[]=1&numbers[]=2

Or to a 1 indexed "list"

?numbers[1]=1&numbers[2]=2

Or to a comma delimited list

?numbers=1,2

Or just multiple of one instance = enumerable

?numbers=1&numbers=2

And probably a lot more formats. But all of these are framework/ implementation specific of whatever is receiving these calls as there is no official standard, and the same goes for something like

class Foo
{
public AuthEndPointArgs Args { get; set; }
}

Could be

?args.response_type=code&args.client_id=a%3Ab

And a bunch more different ways I can't be bothered to think off right now

Standardized way to serialize JSON to query string?

URL-encode (https://en.wikipedia.org/wiki/Percent-encoding) your JSON text and put it into a single query string parameter. for example, if you want to pass {"val": 1}:

mysite.com/path?json=%7B%22val%22%3A%201%7D

Note that if your JSON gets too long then you will run into a URL length limitation problem. In which case I would use POST with a body (yes, I know, sending a POST when you want to fetch something is not "pure" and does not fit well into the REST paradigm, but neither is your domain specific JSON-based query language).



Related Topics



Leave a reply



Submit