Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Trying to create something really lightweight. Sources are on GitHub.

To create a proxy we need to define an interface first, e.g.:

// Fake Online REST API for Testing and Prototyping
[Site("https://jsonplaceholder.typicode.com")]    
public interface ITypicode
{
    [Get("posts")]
    Task<BlogPost[]> GetAsync();

    [Get("posts/{0}")]
    Task<BlogPost> GetAsync(int id);

    [Post("posts")]
    Task<BlogPost> PostAsync([Body] BlogPost data);

    [Put("posts/{0}")]
    Task<BlogPost> PutAsync(int id, [Body] BlogPost data);

    [Delete("posts/{0}")]
    Task<BlogPost> DeleteAsync(int id);
}

public class BlogPost
{
    public int UserId { get; set; }
    public int Id { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
}

At this moment we actually know enough to generate a proxy:

ITypicode typicode = RestClient.Create<ITypicode>();
BlogPost blogPost = await typicode.PutAsync(1, new BlogPost { Body = "Wow!" });
Console.WriteLine(blogPost.Body);

We can inject HttpMessageHandler:

ITypicode typicode = RestClient.Create<ITypicode>(handler);

We can also emit the proxy class for dependency injection:

Type typicodeType = RestClient.Emit<ITypicode>();

About error handling – this exception is thrown for unsuccessful HTTP status codes:

public class RestException : Exception
{
    public RestException(HttpResponseMessage response)
    {
        Response = response;
    }

    public HttpResponseMessage Response { get; }
    public override string ToString() => 
        Response.Content.ReadAsStringAsync().Result;
}

We could specify extra type parameter for the SiteAttribute:

[Site("https://jsonplaceholder.typicode.com", Error = typeof(TypicodeError))]
public interface ITypicode
{
    // …
}

to have generic exception be thrown instead:

 public class RestException<TError> : RestException
{
    public RestException(HttpResponseMessage response)
        : base(response)
    {
    }

    public T Error => JsonConvert.DeserializeObject<TError>(ToString());
}

So error response body will be kindly deserialized for us.

It is possible to implement API interface on a server side ASP.NET Web API Controller also to insure compatibility.

What do you think about this design?

To be continued with implementation details.


UPDATE: Adding support for HTTP headers – something like this:

[Site("https://jsonplaceholder.typicode.com")]
public interface ITypicode
{
    [Get("posts/{0}")]
    [Header("X-API-KEY: {1}")]   // req - in
    [Header("Content-Type: {2}; charset={3}")]  // res - out
    Task<BlogPost> GetAsync(
        int id, string apiKey, out string contentType, out string charset);    
}

Does it look good? Anything else that might be useful?

share|improve this question
    
P.S. I started it yesterday, so it is definitely rough ;) – Dmitry Nogin Sep 4 at 17:24

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.