Skip to content

Instantly share code, notes, and snippets.

@71
Last active June 1, 2016 18:40
Show Gist options
  • Save 71/7232228013b2a82e44122046ec6bf868 to your computer and use it in GitHub Desktop.
Save 71/7232228013b2a82e44122046ec6bf868 to your computer and use it in GitHub Desktop.
/*
______ _____ _____ _____ _ _ ___________ _____
| ___ \ ___/ ___|_ _| | | || ___| ___ \ _ |
| |_/ / |__ \ `--. | | | |_| || |__ | |_/ / | | |
| /| __| `--. \ | | | _ || __|| /| | | |
| |\ \| |___/\__/ / | | | | | || |___| |\ \\ \_/ /
\_| \_\____/\____/ \_/ \_| |_/\____/\_| \_|\___/
A single file to make easy Rest requests.
UNLICENSED: <http://unlicense.org/UNLICENSE>
*/
/*
Usage:
Hero = new RestHero(new HttpClient() { BaseAddress = "http://example.com" })
.AddHeaders(Authorization => String.Format("Bearer {0}", Token));
await Hero
.Get<MyClass>("/{0}/user", Version)
.Query(anonymized => true)
.Success(async (user) => await DoSomething(user))
.Failure(errCode => throw new Exception(errCode))
.Execute();
*/
namespace Jee
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public sealed class RestHero : IDisposable
{
private HttpClient c;
private CacheProviderDelegate cacheGetter;
private AddToCacheDelegate cacheSetter;
private Func<JObject, bool> m_validatorJson;
private Func<string, bool> m_validatorStr;
private Func<HttpResponseMessage, bool> m_validatorRes;
private DeserializeDelegate m_deser;
private SerializeDelegate m_ser;
public delegate bool CacheProviderDelegate(string url, out string data);
public delegate void AddToCacheDelegate(string url, string data);
public delegate object DeserializeDelegate(string src, Type target);
public delegate string SerializeDelegate(object obj);
public RestHero(HttpClient client)
{
c = client;
m_ser = (obj) =>
{
return JsonConvert.SerializeObject(obj);
};
m_deser = (str, type) =>
{
return JsonConvert.DeserializeObject(str, type);
};
}
public RestHero AddHeaders(params Expression<Func<string, string>>[] headers)
{
foreach (var expr in headers)
c.DefaultRequestHeaders.Add(expr.Parameters[0].Name, expr.Body is ConstantExpression
? (string)((ConstantExpression)expr.Body).Value
: expr.Compile()(""));
return this;
}
public RestHero RemoveHeaders(params string[] headers)
{
foreach (string header in headers)
c.DefaultRequestHeaders.Remove(header);
return this;
}
public RestHero CacheGetter(CacheProviderDelegate provider)
{
cacheGetter = provider;
return this;
}
public RestHero CacheSetter(AddToCacheDelegate add)
{
cacheSetter = add;
return this;
}
public RestHero Validator(Func<JObject, bool> validator)
{
m_validatorJson = validator;
return this;
}
public RestHero Validator(Func<string, bool> validator)
{
m_validatorStr = validator;
return this;
}
public RestHero Validator(Func<HttpResponseMessage, bool> validator)
{
m_validatorRes = validator;
return this;
}
public RestHero Serializer(SerializeDelegate sd)
{
m_ser = sd;
return this;
}
public RestHero Deserializer(DeserializeDelegate dd)
{
m_deser = dd;
return this;
}
public Request<T> Get<T>(string url, params object[] args)
{
return new Request<T>(this, new HttpRequestMessage(HttpMethod.Get, String.Format(url, args)));
}
public Request<T> Delete<T>(string url, params object[] args)
{
return new Request<T>(this, new HttpRequestMessage(HttpMethod.Delete, String.Format(url, args)));
}
public Request<T> Post<T>(string url, params object[] args)
{
return new Request<T>(this, new HttpRequestMessage(HttpMethod.Post, String.Format(url, args)));
}
public Request<T> Put<T>(string url, params object[] args)
{
return new Request<T>(this, new HttpRequestMessage(HttpMethod.Put, String.Format(url, args)));
}
public void Dispose()
{
c.Dispose();
}
#region Request
public class Request<T>
{
public delegate void SuccessCallback(T obj);
public delegate Task AsyncSuccessCallback(T obj);
public delegate void FailureCallback(HttpStatusCode statusCode);
public delegate Task AsyncFailureCallback(HttpStatusCode statusCode);
private SuccessCallback m_scb;
private FailureCallback m_fcb;
private AsyncSuccessCallback m_ascb;
private AsyncFailureCallback m_afcb;
private RestHero h;
protected HttpRequestMessage req;
internal Request(RestHero hero, HttpRequestMessage msg)
{
h = hero;
req = msg;
}
#region Callbacks
public Request<T> Success(SuccessCallback callback)
{
m_scb = callback;
return this;
}
public Request<T> Success(AsyncSuccessCallback callback)
{
m_ascb = callback;
return this;
}
public Request<T> Failure(FailureCallback callback)
{
m_fcb = callback;
return this;
}
public Request<T> Failure(AsyncFailureCallback callback)
{
m_afcb = callback;
return this;
}
public async Task<T> Execute()
{
return await Execute(false);
}
public async Task<T> Execute(bool throwOnError)
{
HttpResponseMessage msg = await h.c.SendAsync(req);
if ((h.m_validatorRes == null && msg.IsSuccessStatusCode) || (h.m_validatorRes != null && h.m_validatorRes(msg)))
{
T obj;
if (typeof(T) == typeof(byte[]))
obj = (T)(object)await msg.Content.ReadAsByteArrayAsync();
else if (typeof(T) == typeof(Stream))
obj = (T)(object)await msg.Content.ReadAsStreamAsync();
else
{
string content = await msg.Content.ReadAsStringAsync();
JObject jo = null;
if ((h.m_validatorJson != null && !h.m_validatorJson((jo = JObject.Parse(content))))
|| (h.m_validatorStr != null && !h.m_validatorStr(content)))
{
if (m_afcb != null)
await m_afcb(msg.StatusCode);
else if (m_fcb != null)
m_fcb(msg.StatusCode);
return default(T);
}
if (jo == null)
jo = JObject.Parse(content);
if (typeof(T) == typeof(String))
obj = (T)(object)content;
else
obj = Deserialize(content);
}
if (m_ascb != null)
await m_ascb(obj);
else
m_scb(obj);
return obj;
}
else
{
if (m_afcb != null)
await m_afcb(msg.StatusCode);
else if (m_fcb != null)
m_fcb(msg.StatusCode);
}
return default(T);
}
#endregion
#region Additional content
public Request<T> Query(params Expression<Func<string, object>>[] queryParams)
{
StringBuilder query = new StringBuilder();
for (int i = 0; i < queryParams.Length; i++)
{
query.Append(i == 0 && req.RequestUri.OriginalString.IndexOf('?') == -1 ? '?' : '&');
query.Append(queryParams[i].Parameters[0].Name);
query.Append('_');
query.Append(Serialize(queryParams[i].Body is ConstantExpression
? ((ConstantExpression)queryParams[i].Body).Value
: queryParams[i].Compile()("")));
}
req.RequestUri = new Uri(req.RequestUri.OriginalString + query.ToString());
return this;
}
public Request<T> Body<TBody>(object obj)
{
req.Content = new StringContent(Serialize(obj));
return this;
}
private string Serialize(object o)
{
if (o is string) return (string)o;
else if (o is short || o is int || o is long || o is ushort || o is uint || o is ulong
|| o is float || o is double || o is bool || o is char || o is string || o is byte) return Convert.ToString(o);
else if (o is IntPtr || o is UIntPtr) return o.ToString();
else return h.m_ser(o);
}
private T Deserialize(string str)
{
return (T)h.m_deser(str, typeof(T));
}
#endregion
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment