Skip to content

Instantly share code, notes, and snippets.

@nsantorello
Created December 15, 2014 18:12
Show Gist options
  • Save nsantorello/1a8a45d75a4df6980dfb to your computer and use it in GitHub Desktop.
Save nsantorello/1a8a45d75a4df6980dfb to your computer and use it in GitHub Desktop.
JsonConverter for easily deserializing Contentful API responses with JSON.NET
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using System.Text;
namespace Grounded
{
public class ContentfulLinkConverter : JsonConverter
{
private Dictionary<string, JObject> _includes;
private Type _excludedType;
// This flag makes it so that the first call to CanConvert that passes the excluded type will return false.
// Rather than excluding the type, we'll have to just fail the very first call
// since it will be the type we are trying to convert. If we exclude the type
// we're deserializing, then we won't be able to deserialize references it has
// to its own type.
private bool _canConvertFlag = false;
public ContentfulLinkConverter (Dictionary<string, JObject> includes, Type excludedType)
{
_includes = includes;
_excludedType = excludedType;
}
#region implemented abstract members of JsonConverter
public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException ();
}
public override object ReadJson (JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var json = JObject.Load (reader);
var id = json ["sys"] ["id"].ToString ();
var linkType = json ["sys"] ["linkType"].ToString ();
if (!_includes.ContainsKey (id)) {
throw new JsonException ("The object with the ID '" + id + "' was not included in the JSON response.");
}
return JsonConvert.DeserializeObject (
linkType == "Asset" ? _includes[id]["fields"]["file"].ToString() : _includes [id] ["fields"].ToString(),
objectType,
new ContentfulLinkConverter(_includes, objectType));
}
public override bool CanConvert (Type objectType)
{
var isExcluded = objectType.Equals (_excludedType);
var canConvert = (_canConvertFlag || !isExcluded) && objectType.Namespace == this.GetType ().Namespace;
if (isExcluded) {
_canConvertFlag = true;
}
return canConvert;
}
#endregion
}
}
// This assumes you know the type of the objects in the response, and they are all
// the same Contentful type. If not, minor modifications will be necessary.
private void ContentfulSuccess(string resp)
{
JObject json = JObject.Parse (resp);
if (json == null || json["items"] == null)
return;
// Create mapping of included files by ID to prevent an n^2 operation.
var includes = new Dictionary<string, JObject> ();
var jsonIncludes = json ["includes"] ["Entry"].Concat (json ["includes"] ["Asset"]);
foreach (JObject include in jsonIncludes) {
includes [include ["sys"] ["id"].ToString()] = include;
}
// MyType = some type that maps JSON properties to C# properties with the JsonPropertyAttribute
var deserializedObjects = new List<MyType> ();
foreach (JObject obj in json["items"]) {
deserializedObjects.Add(JsonConvert.DeserializeObject<MyType> (
obj ["fields"].ToString(), new ContentfulLinkConverter(includes, typeof(MyType))));
}
// Do something with deserializedObjects list!
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment