Reputation: 97
The scenario is something like this:
I have this web-api which will handle a variety of payment gateways, and I want to have the same endpoint for all of those.
So, what I have in mind is to get some json data like this:
{
"OperationId":"N0004",
"Generic_Object_That_Will_Change_According_ToThe_GateWay":
{
"Sale_id":1000,
"CodUser":"1000040",
"Email":"[email protected]"
}
}
Or this, for some other payment gateway
{
"OperationId":"N044444",
"Generic_Object_That_Will_Change_According_ToThe_GateWay":
{
"Token":1000,
"UserSettings":{
id: "4563345",
name: "Average Joe"
}
}
}
What I want to do is to transform this "Generic_Object_That_Will_Change_According_ToThe_GateWay" in the specific object for each payment gateway (paypal, or some other), becase each one is completely different, but I don't want that to affect the way the client will call this API - I want it to be as flexible as possible, in a way that you just have to pass whatever data in this Generic_Object_That_Will_Change_According_ToThe_GateWay, and I will then cast it to the proper object and then call another endpoint(like an aggragate microservice design) passing this newly created object.
My idea so far, was creating some class with a generic property like this
public class Payment<Gateway>
{
public int OperationId{ get; set; }
public Gateway paymentGateWay{ get; set; }
}
And this property paymentGateWay could be typed according the available payment Gateways.
And then maybe I could get this data in the API method as Object, and do the necessary casts
[Route("api/payment")]
[HttpPost]
public string Compra(Object payment) {
But, to be honest, I don't know if I'm in the right way.
I already know that I can't have a generic method in a web-api endpoint - so what would be the correct way to get this data in my endpoint considering that a part of this json data is flexible/generic and may be cast to a few different objects.
To summarize, I want to handle json data that can be deserialized to a few different known objects, but I don't want to have a different method in my API to handle each one this possible data scenarios.
Upvotes: 5
Views: 10736
Reputation: 11
Additionally to what @BRAHIM Kamel said, you could use JToken
and it would work for both Json Objects (JObject
) AND Json Arrays (JArray
).
Upvotes: 0
Reputation: 1869
You can have a generic controller to implement the method and instance-controllers, which inherit of the generic controller:
// I'll rename Gateway to TGateway according to the fact, that it is a generic Type parameter.
public class Payment<TGateway>
{
public int OperationId{ get; set; }
public TGateway paymentGateWay{ get; set; }
}
GenericController:
// Don't add a RouteAttribute to this Controller.
public class GenericController<TGateway>: ApiController
{
// The implementation of the method. No RouteAttribute.
[HttpPost]
public string Compra(Payment<TGateway> payment) {...}
}
InstanceController:
// No need to override the method. RouteAttribute.
[Route("api/payment/"+typeof(AGateway).Name)]
public class AGatewayController : GenericController<AGateway>
{}
Upvotes: 0
Reputation: 13755
if you want a generic method in webapi you have to use JObject something like the following
public void Post([FromBody] JObject testJObject)
{
//here you have to do some additional work in order to parse and get it working for generic entity
}
in addition to this, you can use the Schema validator against any received request and use the factory pattern in order to create the correct object
here an example
var json =
" {\"OperationId\":\"N0004\",\"Generic_Object_That_Will_Change_According_ToThe_GateWay\":{\"Sale_id\":1000,\"CodUser\":\"1000040\"}}";
JsonSchema paypalschema = new JsonSchema();
paypalschema.Type = JsonSchemaType.Object;
paypalschema.Properties = new Dictionary<string, JsonSchema>
{
{"OperationId", new JsonSchema {Type = JsonSchemaType.String}},
{
"Generic_Object_That_Will_Change_According_ToThe_GateWay",
new JsonSchema {Type = JsonSchemaType.Object,Properties = new Dictionary<string, JsonSchema>
{
{"Sale_id", new JsonSchema {Type = JsonSchemaType.Integer}},
{"CodUser", new JsonSchema {Type = JsonSchemaType.String}},
}}
}
};
JObject requestObject = JObject.Parse( json);
bool valid = requestObject.IsValid(paypalschema);
if (valid)
{
//create your GatewayObject here
}
//else check another gateway object
Upvotes: 4
Reputation: 168
Consider using JObject or String as your input (And then converting to JObject.) Then you can do some type or data checking before casting. Here's an example shows how they use a pre-defined 'type' value provided, but in lieu of that, you can instead look in the JObject for the 'parts' of each unique provider's payload to determine which type to use.
Upvotes: 0