Last active
June 1, 2016 18:40
-
-
Save 71/7232228013b2a82e44122046ec6bf868 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
______ _____ _____ _____ _ _ ___________ _____ | |
| ___ \ ___/ ___|_ _| | | || ___| ___ \ _ | | |
| |_/ / |__ \ `--. | | | |_| || |__ | |_/ / | | | | |
| /| __| `--. \ | | | _ || __|| /| | | | | |
| |\ \| |___/\__/ / | | | | | || |___| |\ \\ \_/ / | |
\_| \_\____/\____/ \_/ \_| |_/\____/\_| \_|\___/ | |
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