xdtTransform
xdtTransform

Reputation: 2057

Multiple return type from API

Input and API definition :

I'm consuming the following API, that responde either with a Data object of an Error object

FooBar Method: Ids is a list of string separated by commas

GET: /FooBar/v1{?ids}
GET: /FooBar/v1/{ids}

Request Header:

X-FooBar-Key:   ## My key ##

Response : 200

// if there is multiple IDs, response is an array of Data and Error
[{
  "data": { }
}, {
  "data": { }
}, {
  "error": { }
}]

//If there is only one ID, response is the content of the data object
{
    "code":     "",
    "date":     "",
    "status":   "",
    "message":  "",
    "link":     "",
    "type":     ""
}

Response : 400/404/etc , Return the content of an Error object

{
    "code":     "",
    "message":  ""
}

Output and Expected results:

I want to be able to check [1, N] IDs and with only one object return type Response with either Data or Error initialised the other at null...

public class Response
{
    [JsonProperty("data")]
    public Data Data { get; set; }

    [JsonProperty("error")]
    public Error Error { get; set; }

    public string Id{  get; set; }
} 
public class Error
{
    [JsonProperty("message")]
    public string Message { get; set; }

    [JsonProperty("code")]
    [JsonConverter(typeof(StringEnumConverter))]
    public ErrorCode Code { get; set; }
}    
public class Data
{
    [JsonProperty("status")]
    [JsonConverter(typeof(StringEnumConverter))]
    public Status Status { get; set; }

    [JsonProperty("type")]
    public string Type { get; set; }

    [JsonProperty("code")]
    public string Code { get; set; }

    [JsonProperty("date")]
    public string Date { get; set; }

    [JsonProperty("message")]
    public string Message { get; set; }

    [JsonProperty("link")]
    public string Link { get; set; }
}

Attempt:

In order to simply the problem For now I work only on 1 Id at a time.
Using ServiceStack Client to consume the REST API.

public class FooBarAPI : IFooBarAPI
{
    Dictionary<string, string> DefaultHeader;
    string BasePath; // https://foofoo.bar/FooBar/v1
    public FooBarAPI(Dictionary<string, string> defaultHeader, string basePath)
    {
        DefaultHeader = defaultHeader;
        BasePath = basePath;
    }

    public Response GetFooBar(string id)
    {
        JsonServiceClient client = new JsonServiceClient(BasePath);
        client.RequestFilter = httpReq => httpReq.Headers.Add("X-FooBar-Key", DefaultHeader["X-FooBar-Key"]);

        var response = 
                client.GetAsync<Response>($"/{id}");    // Null as for one ID the result is type Data not Response
                // client.GetAsync<Data>($"/{id}");     // Working If not Error  

        var toto = response.Result;
        toto.Id = id;

        return toto;
    }

    public Response[] GetFooBar(string[] ids)
    {   // 
        throw new NotImplementedException();
    }
}

This question is not tagged with ServiceStack as I'm open to solution using : HttpWebRequest/Response Class, WebClient Class, HttpClient Class, RestSharp NuGet Package, ServiceStack Http Utils, Or Anything that make my life easier.

I am using ServiceStack because of documentation saying that I could use something like :

client.GetAsync(new Hello { Name = "World!" })
    .Success(r => r => r.Result.Print())
    .Error(ex => { throw ex; });

Using Success and Error to map single return type to my Response type.

Upvotes: 3

Views: 3593

Answers (2)

mythz
mythz

Reputation: 143284

ServiceStack C#/.NET Service Clients supports both Sync and Async APIs, since your method is synchronous you should only be using the synchronous APIs, e.g:

public Response GetFooBar(string id)
{
    var client = new JsonServiceClient(BasePath) { 
        RequestFilter = req => req.Headers.Add(
            "X-FooBar-Key", DefaultHeader["X-FooBar-Key"])
    }

    try 
    {
        var response = client.Get<Response>($"/{id}");
        response.Id = id; // Why isn't this already in the response?
        return response;
    }
    catch (WebServiceException ex)
    {
        //Error Details
        //ex.StatusCode;
        //ex.ErrorCode;
        //ex.ErrorMessage;
    }
}

You should only use the async APIs if your method is also async, e.g:

public async Task<Response> GetFooBar(string id)
{
    var client = new JsonServiceClient(BasePath) { 
        RequestFilter = req => req.Headers.Add(
            "X-FooBar-Key", DefaultHeader["X-FooBar-Key"])
    }

    try 
    {
        var response = await client.GetAsync<Response>($"/{id}");
        response.Id = id; // Why isn't this already in the response?
        return response;
    }
    catch (WebServiceException ex)
    {
        //Error Details
        //ex.StatusCode;
        //ex.ErrorCode;
        //ex.ErrorMessage;
    }
}

Upvotes: 1

dannybucks
dannybucks

Reputation: 2355

If you are using ServiceStack, then you should use it the way you found in the doc, but this would mean that you actually throw (a custom) exception when ever the id does not exist. Your custom exception would then include the code and message. So you would actually just throw an exception when ever you want to return an error.

However, I don't think that is what you should do, because exceptions should only be used if an exceptional case happens, but as far as I understand, errors is a common and normal behavior that happens often (like the client does try and error with ids). Therefore, I recommend using HttpWebResponse Class as your return type. There you can basically set the HTTP return state (e.g. 400, 404) and json (or actually any) data.

Upvotes: 1

Related Questions