1

Say I want to create a C# implementation of an API for some 3rd party service, and I want to have an option to get the json posts and responses out somehow, what would be an elegant way of doing that?

Example of a method:

public class MyApiImplementation{
    public PaymentRespose CreatePayment(decimal amount, string orderId){
        //some code here
    }
}

When I call that method (compiled), I want to get the json form the underlying rest response, so I can debug it or log it.

I don't want to do something like this...:

public class MyApiImplementation{
    public PaymentRespose CreatePayment(decimal amount, string orderId, out string json){
        //some code here
    }
}

When I call the api, I want to be able to get the json out somehow.

public api = new MyApiImplementation();
PaymentResponse pr = api.CreatePayment(100M, "ORDER1234");
string json = ???

I could include the json in the PaymentResponse, but... It seems like it does not belong there.

I am thinking an optional logger of some sort in a contructor overload.

Any good suggestions on how to implement this? What could it look like?

Edit:

Followup

I don't think I was clear enough in my description, so let me try to elaborate and provide a bit more code.

Purpose

I am creating a library class, which is a C# wrapper around a REST interface for a payment provider. I will provide this library to developers via Nuget.

This is what I do today

public class AwesomePaymentClient{
    public Payment CreatePayment(string orderId, string currency, out string json)
    {
        var request = CreatePostRequest("payments");

        request.AddParameter("currency", currency);
        request.AddParameter("order_id", orderId);

        var response = Client.Execute<Payment>(request);
        json = response.Content;
        VerifyResponse(response);

        return response.Data;
    }
    //all other methods omitted from example
}

I don't particularly like the

out string json
bit, but I would like developers to have a way to get the actual json response for their own debugging/logging purposes.

I could create an overload that does not have the out parameter, but I feel it makes the API kind of dirty - and that it is a separate concern.

I could also include a json property on Payment-class, but again I would like to keep it separate.

So I am thinking, maybe I make a contructor overload, that takes in some kind of logger or... Something, that I can't quite figure out what is.

Middleware etc is out of the question, as I am just providing a library.

Hope this helps in making my intentions clearer. :)

  • 1
    What platform? If your using .net core you would write some middleware in your request pipeline to log the request/response. If older style asp.net you could implement IHttpHandler, or if your only wanted to log for a particular controller use a filter. – Jon Raynor Nov 8 '17 at 18:42
  • If PaymentResponse is an object one can use Newtonsoft and just pass the object... var jsonData = JsonConvert.SerializeObject(data); So, just pass the object into the serializer and get back the json string. So I would separate out the CreatePayment versus the serialization. – Jon Raynor Nov 8 '17 at 19:16
  • For what reason do you want to store the JSON responses? – whatsisname Nov 9 '17 at 4:26
  • @JonRaynor i think the OP suggests that they want to store requests to some endpoint they don't control, so handlers and middleware might not work. – zaitsman Nov 9 '17 at 6:54
  • To answer your question, you need to provide the //some code here bit that you've omitted - that is where any such logging would go :) – zaitsman Nov 9 '17 at 6:55
1

With concurrent access to an instance, the JSON response cannot be stored in a property (because a different request might overwrite its value before it is read).

With a "logger", it is still necessary to somehow find out which JSON response belongs to which request, so you'd need some identifier.

I'd prefer to offer two versions of the interface: a "normal", and an "extended" one, like:

public interface IPaymentClient
{
    IPayment CreatePayment(string orderId, string currency);
}
public interface IPaymentClientEx: IPaymentClient
{
    IPayment CreatePayment(string orderId, string currency, out string json);
}

With implementations like

public class AwesomePaymentClient: IPaymentClient 
{
    public IPayment CreatePayment(string orderId, string currency)
    {
        var request = CreatePaymentRequest(orderId, currency);
        var response = ExecutePaymentRequest(request);
        return response.Data;
    }
    protected IRequest CreatePaymentRequest(string orderId, string currency)
    {
        var request = CreatePostRequest("payments");
        request.AddParameter("currency", currency);
        request.AddParameter("order_id", orderId);
        return request;
    }
    protected IResponse ExecutePaymentRequest(IRequest request)
    {
        var response = Client.Execute<Payment>(request);
        VerifyResponse(response);
        return response;
     }
}
public class AwesomePaymentClientEx: AwesomePaymentClient, IPaymentClientEx
{
    public IPayment CreatePayment(string orderId, string currency, out string json)
    {
        var request = CreatePaymentRequest(orderId, currency);
        var response = ExecutePaymentRequest(request);
        json = response.Content;
        return response.Data;
    }
}

Now the developer can choose which version he needs. It is not perfectly clean, but I guess it comes closer to your requirements. And the "extended" version still offers the "normal" functions also.

  • I like this approach. I don't think there is a cleaner way to accomplish this. :) – Kjensen Nov 9 '17 at 14:41
2

The API should include a logger interface for each method that is being exposed. Maybe something like this:

public IPayment CreatePayment(string orderId, string currency, ILogger logger)

Then each consumer of the API could implement the logger as they see fit passing in a logger implementation.

In the method call, simply add (or similar):

Logger.LogResponse(string response);

Then the logging implemention will do the logging to file, db, etc. The consumer of your API will will decide. Internally handle the conversion/serialization of the JSON as you see fit.

You provide the interface, your API consumers implement. If there was no implantation passed (null), you could have an internal implementation that uses System.Diagnostics or similar.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.