API的多种返回类型

时间:2019-03-21 10:06:01

标签: c# rest

输入和API定义:

我正在使用以下API,它们以Data对象的Error对象作为响应

FooBar方法:Ids是用逗号分隔的字符串列表

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

请求标头:

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

响应: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":     ""
}

响应:400/404 / etc,返回错误对象的内容

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

输出和预期结果:

我希望能够检查[1,N]个ID,并且只有一个对象返回类型Response,其中Data或Error都将其初始化为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; }
}

尝试:

为了简单地解决问题,现在我一次只能处理1个ID。
使用ServiceStack Client使用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();
    }
}

此问题未用ServiceStack标记,因为我愿意使用以下方法解决方案: HttpWebRequest / Response类, WebClient类, HttpClient类, RestSharp NuGet软件包, ServiceStack Http Utils,或任何使我的生活更轻松的事情。

我之所以使用ServiceStack,是因为documentation说我可以使用类似的东西:

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

使用SuccessError将单返回类型映射为我的Response类型。

2 个答案:

答案 0 :(得分:1)

如果您正在使用ServiceStack,则应按在文档中找到的方式使用它,但这意味着您实际上会在id不存在时实际抛出(自定义)异常。然后,您的自定义异常将包含代码和消息。因此,当您想返回错误时,您实际上只会抛出异常。

但是,我不认为这是您应该做的,因为只有在例外情况发生时才应使用异常,但据我所知,错误是经常发生的常见且正常的行为(例如客户)会尝试并使用ID出错)。因此,我建议使用HttpWebResponse类作为您的返回类型。在那里,您基本上可以设置HTTP返回状态(例如400、404)和json(或实际上任何)数据。

答案 1 :(得分:0)

ServiceStack C#/.NET Service Clients支持同步和异步API,因为您的方法是同步的,所以您只应使用同步API,例如:

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;
    }
}

如果您的方法也是异步的,则应该使用异步API,例如:

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;
    }
}