How Can I validate the JSON body of an API call in a separate method - rest-assured

Trying to validate some JSON values outside of the first method. What would be the best way to do that in the second method ?
#When("^User sends API request with (.*) and no qualifiers and an State Code entry level T1.3$")
public void user_sends_API_request_with_no_qualifiers_and_an_entry_level_T(String path) {
response =
given()
.auth().oauth2(DomaniRx_RestAssuredOAuth2.access_token_code)
.queryParam("PhamacyID","12345")
.queryParam("Customer Set Type ID", "CustomerSetTypeValue")
.queryParam("PharmacyListIDShortName","Value")
.queryParam("DateFilled","04/17/2022")
.get(defaultURL+path)
.then()
.statusCode(200)
.extract().response();
}
#Then("^The Pharmacy ID in the response should match the (\\d+) in the request T1.3$")
public void the_Pharmacy_ID_in_the_response_should_match_the_in_the_request_T(String PharmacyID) {
}

I don't know the best way, but I think one way to achieve that is put response is an instance variable, then you can access it from other method in same class.
If you want to share response outside class, then use class (static) variable

You can assign your response body to a variable like the below:
Then you can make assertions easily on the other methods. You can define a ResponseModel according to your response. Its name can be changed. it's up to you.
private ResponseModel response;
.
response =
given()
.auth().oauth2(DomaniRx_RestAssuredOAuth2.access_token_code)
.queryParam("PhamacyID","12345")
.queryParam("Customer Set Type ID", "CustomerSetTypeValue")
.queryParam("PharmacyListIDShortName","Value")
.queryParam("DateFilled","04/17/2022")
.get(defaultURL+path)
.then()
.statusCode(200)
.extract().response()
.jsonPath().getObject(".", ResponseModel .class);

Related

How to return view along with model in Async task in Asp.Net MVC

I am testing asynch task in MVC and creating asynchronous task following code. When I return model value along with view name return View("Index", EmpResponse), I am getting error. but if I simply return view return view(). it is working well.
public class AsynchController : Controller
{
string Baseurl = "http://dummy.restapiexample.com/api/v1/";
// GET: Asynch
public async Task<ActionResult> Index()
{
using (var client = new HttpClient())
{
//Passing service base url
client.BaseAddress = new Uri(Baseurl);
client.DefaultRequestHeaders.Clear();
//Define request data format
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Sending request to find web api REST service resource GetAllEmployees using HttpClient
HttpResponseMessage Res = await client.GetAsync("employees");
var EmpResponse = "";
//Checking the response is successful or not which is sent using HttpClient
if (Res.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
EmpResponse = Res.Content.ReadAsStringAsync().Result;
//Deserializing the response recieved from web api and storing into the Employee list
}
//returning the employee list to view
return View("Index", EmpResponse);
}
}
In simply ActionResult, I know we can return view name and model both together. is it issue with Async task?
Your intention is to pass EmpResponse as the view-model for your Index view, but since you have already deserialized EmpResponse as a string, it matches the wrong overload of the View() helper method (the one which accepts both viewName and masterName).
Try to pass it as an object to match the correct overload:
return View("Index", EmpResponse as object);
A better approach would be to store the received data as a strongly-typed collection of objects:
var empResponse = await Res.Content.ReadAsAsync<IEnumerable<Employee>>();
Then pass it as a view-model:
return View("Index", empResponse);
This isn't really an async issue, but a model type issue. (Though there is an async issue waiting to become a problem... Don't call .Result directly, but instead use await to get the result.)
Your model is a string. But the overload for View() which takes a second string uses it to find a named view. Which is why it's looking for a view called your long JSON string. (Well, a "master view" in this case since you're sending it two strings.)
Don't use a string as a model. Use a model. Instead of sending one big JSON string to your view, deserialize it into a model of some sort. The type is up to you, but the deserialization might look something like:
var response = await client.GetAsync("employees");
YourModelTypeHere model = null;
if (response.IsSuccessStatusCode)
{
var responseString = await result.Content.ReadAsStringAsync();
model = JsonConvert.DeserializeObject<YourModelTypeHere>(responseString);
}
return View(model);
There may even be an option in result to read/deserialize as your model directly, saving you a line of code above. But the overall principle is the same. Use strongly typed models instead of complex serialized strings.
*In this case, YourModelTypeHere looks like it would in fact be an IEnumerable<YourModel> or perhaps an IList<YourModel>, based on the serialized JSON we're seeing.
*Note also that this uses your current logic of sending an empty model to the same view if nothing was successfully retrieved. For an empty string that may be okay, for null it may become problematic depending on what your view is doing. (Either way your view is going to have to change if it currently expects a string as a model.) Perhaps redirect or return an error in the case of no available model? The logic of how your system should behave is up to you.

How to handle a POST method that also has a parameter of unknown type?

I am coding to handle a Facebook callback. Facebook calls the same Url with POST but with different object types. I am not ready to handle all the parameter types, so I tried the following:
public void Post([FromBody]class1 webhook1)
{ // for object1
}
public void Post([FromBody]class2 webhook2)
{ // for object12
}
public async Task Post()
{
string rawData = await Request.Content.ReadAsStringAsync();
log(rawData);
}
However, I get this exception:
"Multiple actions were found that match the request ...
Is there a way to allow a fallback option for parameter types I am not ready to handle?
Method overloading based on the type of parameter is not supported for "web" routing methods
Use route attribute:
[Route("webhook1")]
public void Post([FromBody]class1 webhook1) {}
[Route("webhook2")]
public void Post([FromBody]class2 webhook2) {}
Or if you don't want client side to know about different parameter's types,
then make one "web" method where you read raw data from the body of request,
detect a type of data and call correspondent method to handle it
You may want to use attribute based routing instead as this gives you a lot more flexibility. Web api donot support standard routing methods well.
It should be something like this:
[RoutePrefix("api/example")]
public ExampleController : ApiController{
[Route("postwebhook1")]
public void Post([FromBody]class1 webhook1)
{ // for object1
}
[Route("postwebhook2")]
public void Post([FromBody]class2 webhook2)
{ // for object12
}
[Route("post")]
public async Task Post()
{
string rawData = await Request.Content.ReadAsStringAsync();
log(rawData);
}
}

What is the correct REST Urlpattern for POST operation

I have rest url support POST request. its looks like
api/country/{countryId}/state
using to create state resource in a country with given id
but the mapping function of this url is
public HttpResponseMessage Post(int countryId,StateDto state)
{
var country = _countryAppService.AddNewState(state, countryId);
var message = Request.CreateResponse(HttpStatusCode.Created, country);
return message;
}
and expected sample of the given urls is like
api/country/1/state (create a new state in country with id=1)
but here i am not using the url value (1) in the above function instead of here the caller need to pass the corresponding countryId via request body, ie there is no any guarantee to both contryId in url and post request are same. so my doubt is what is the right url pattern to save a state in particular country vai a post request?
If you have the same information in the resource path and the request body, it's duplication of information; the caller should never need to pass you the same information twice in the same request.
You should pick one as the authoritative source and ignore the other. Since you must have the correct resource address to perform the operation, I would suggest you need to take the value from there:
public HttpResponseMessage Post(int countryId,StateDto state)
{
// Compose the DTO from the route parameter.
state.CountryId = countryId;
var country = _countryAppService.AddNewState(state);
var message = Request.CreateResponse(HttpStatusCode.Created, country);
return message;
}
You can pass StateDto object in body also,it will go in body ,id can go in url
public HttpResponseMessage Post([FromUri]int countryId,[FromBody]StateDto state)
{
var country = _countryAppService.AddNewState(state, countryId);
var message = Request.CreateResponse(HttpStatusCode.Created, country);
return message;
}
Only one param can come from body , other have to come from uri, you can read more here:
http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
Passing stateDto in uri is also an option but then you will have to pass all its members in querystring.

Change returned object value after action execution in Web API

In ASP.Net Web API, the action returned object will be converted to XML or JSON automatically - is there a way to add additional process to the returned object before it gets converted?
What I want to achieve is to wrap returned object into a generic APIResponse (another class) type which has an object Property called Data that will be assigned with whatever the original returned object is.
for example:
public Books[] FindBooks(string keyword)
{
..
return new Books[] {new Book(){Name="ASP.NET"}};
}
This will return JSON of book array by default, however I want to wrap the result into an object called APIResponse, so the returned object becomes:
new APIResponse(){
Data = //the Book[] array return from the action method
}
By doing this, I will be able to keep the freedom of returning normal business objects in Web API however always return the same object type in JSON format when the front-end Ajax requests.
I believe it can be done in a way however I'm not familiar with the Web API life cycle, can any way give some guide on this?
Thank you.
I fixed it by creating a custom MediaTypeFormatter however simply inheriting from JSON formatter which have already got all what I need, here is the very simple code I added, which resolved all issues I have!!!
public class APIResponseMediaFomatter : JsonMediaTypeFormatter
{
public override Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
{
ResponseMessage wrappedValue = null;
if (type != typeof(ResponseMessage) || (value != null && value.GetType() != typeof(ResponseMessage)))
wrappedValue = new ResponseMessage(value);
return base.WriteToStreamAsync(typeof(ResponseMessage), wrappedValue, writeStream, content, transportContext);
}
}
Cheers!
Interestingly, Web API already works exactly how you describe. It already has generic request and response classes that can hold your object payload. Just do the following,
public HttpResponseMessage FindBooks(string keyword)
{
...
var books = new Books[] {new Book(){Name="ASP.NET"}};
var content = new ObjectContent<Book[]>(books,new JsonMediaTypeFormatter());
return new HttpResponseMessage { Content = content);
}
There is no need to re-invent your own generic response object that can hold metadata and data, HTTP has already done that for you.
Why dont you return your wrapper object APIResponse from WebAPI
public APIResponse FindBooks(string keyword)
{
var books = new Books[] {new Book(){Name="ASP.NET"}};
return new APIResponse {Data= books };
}
Just use an action filter, and modify the response content inside it:
public class ApiResponseWrapperActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
// Check that the response is an object content
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
// Wrap the returned value in the ApiResponse
objectContent.Value = new ApiResponse() { Data = objectContent.Value };
}
}
Apply the filter to the whole API (in global config) or a whole controller (attribute applied to the controller class) or to the desired methods (attribute in each method).
If you're returning something that it's not an object (a custom response) it will skip the wrapping.

StructureMap dynamic set properties per HttpRequest

StructureMap Configuration
Is there a way in SM to dynamically inject property value only for the duration of a request then set the those property back to default after the request is completed?
I'm specifically referring in the HttpRequest context.
I have a IDBAccessor interface and a DBAccessor concrete implementation.
IDBAccessor has a public property for connection string.
I want to set the connectionstring dynamically for each HttpRequest depending on some parameter that is passed in.
Is there an easy to accomplish this?
Thanks for the input.
I assume you have a class that encapsulates the logic to determine the connection string for each request. I'll call it ConnectionStringSource. You could then configure StructureMap like this:
ObjectFactory.Initialize(x =>
{
x.For<IDBAccessor>().HybridHttpOrThreadLocalScoped()
.Use(ctx =>
{
var connectionString = ctx.GetInstance<ConnectionStringSource>().GetConnectionString();
var dbAccessor = new DBAccessor {ConnectionString = connectionString};
return dbAccessor;
});
});
public class ConnectionStringSource
{
public string GetConnectionString()
{
// determine the connection string somehow
return "connection string";
}
}
The HybridHttpOrThreadLocalScoped call will make sure you get a new instance of DBAccessor for each HTTP request. And by using the Func<> overload of Use(), you can execute the code to determine and set the connection string during each request.
Note: You might want to just make the connection string a constructor parameter of DBAccessor instead of making it a property on the interface.

Resources