I'm writing the test inside the developers solution for one service and I'm mocking other third-party party services using pact mock service.
I need to verify the request that was sent to this mock service. So I need to get the payload that was actually sent. (The one that was actually stored into the log file starting with 'Received request ')
I'll greatly appreciate the help
Pact does the verification of the consumer request for you. Have a look at this example.
For the consumer, the test process is:
Describe the expected request
Describe the expected response
Call the code that the consumer uses to generate the response. (This step will actually hit the mock server- which returns the expected response if it gets the expected request).
Verify that the consumer code returned the expected data
Verify that the mock server received the correct request
I've bolded step 5, because that's the step that does the checking of the request.
(note also that if the request was not correct, step 3 doesn't generate the correct response, so step 4 will almost always fail)
Here's a breakdown of the example I linked above into the consumer test steps I've just listed:
Describe the expected request
_mockProviderService
.Given("There is a something with id 'tester'")
.UponReceiving("A GET request to retrieve the something")
.With(new ProviderServiceRequest
{
Method = HttpVerb.Get,
Path = "/somethings/tester",
Headers = new Dictionary<string, object>
{
{ "Accept", "application/json" }
}
})
Describe the expected response
.WillRespondWith(new ProviderServiceResponse
{
Status = 200,
Headers = new Dictionary<string, object>
{
{ "Content-Type", "application/json; charset=utf-8" }
},
Body = new //NOTE: Note the case sensitivity here, the body will be serialised as per the casing defined
{
id = "tester",
firstName = "Totally",
lastName = "Awesome"
}
}); //NOTE: WillRespondWith call must come last as it will register the interaction
Call the code that the consumer uses to generate the response
var consumer = new SomethingApiClient(_mockProviderServiceBaseUri);
//Act
var result = consumer.GetSomething("tester");
Verify that the consumer code returned the expected data
//Assert
Assert.Equal("tester", result.id);
Verify that the mock server received the correct request
_mockProviderService.VerifyInteractions(); //NOTE: Verifies that interactions registered on the mock provider are called once and only once
^ This is the step you need in order to verify that the request sent was correct.
Related
I'm making an http request post to an external api. I am constructing a json object to add to the request body. How can I check if the added body/content is correct before it is sent.
public async void TestAuthentication()
{
var client = new HttpClient();
var request = new HttpRequestMessage()
{
RequestUri = new Uri("http://test"),
Method = HttpMethod.Post
};
var jsonObj = new
{
data = "eneAZDnJP/5B6r/X6RyAlP3J",
};
request.Content = new StringContent(JsonConvert.SerializeObject(jsonObj), Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
}
If you are not sure whether the serialization works as intended, you could give it a shot in LINQpad or dotnetfiddle.net. See my example that returns the JSON on the console. These tools are great for quick prototyping a method or a snippet, if you are not sure if a piece of code works as intended.
You could also check in Wireshark, but that could be a bit of an overkill and works best if your connection if not encrypted (no HTTPS).
I personally tend to test code that calls some API the following way:
Make the called URL parameterizable (via the classes constructor)
If there is any variable data this data should be passed as the methods parameter(s)
For your test start an HTTP server from your test fixture (read on testing with xUnit or NUnit if you don't know what this means)
I use PeanutButter.SimpleHTTPServer for that
Pass the local IP to the class that accesses the API
Check whether the HTTP server received the expected data
Whether or not this kind of code shall be tested (this way) may be debatable, but I found this way to work kind of good. I used to abstract the HttpClient class away, but IMHO I would not recommend this anymore, because if the class accesses the API (and does not do anything else, which is important), the HTTP access is the crucial part that shall be tested and not mocked.
I would like to make a successful API call, then print the values in order to see if it works. My main goal is to analyze the data, after I can make a successful API call, and build a systematic strategy for trading.
System.Net.Http.HttpRequestException: "Response status code does not indicate success: 403 (Forbidden)
namespace marketstacktest
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
var options = Options.Create(new MarketstackOptions() { ApiToken = "secretTokenHere" });
var marketstackService = new MarketstackService(options, NullLogger<MarketstackService>.Instance);
var appleSymbol = "AAPL";
var fromDate = DateTime.Now.AddDays(-200);
var toDate = DateTime.Now;
//error at the await System.Net.Http.HttpRequestException: "Response status code does not indicate success: 403 (Forbidden)."
List<Marketstack.Entities.Stocks.StockBar> stock = await marketstackService.GetStockEodBars(appleSymbol, fromDate, toDate);
foreach (var stock_i in stock)
{
Console.WriteLine($"close: {stock_i.Close}");
}
}
}
}
In the API manual, which is directly linked from the github, it gives information about all of the error codes. The relevant ones here are these two:
Code
Type
Description
403
https_access_restricted
HTTPS access is not supported on the current subscription plan.
403
function_access_restricted
The given API endpoint is not supported on the current subscription plan.
Their class library on github is just wrapping a json REST api. Every call to the API is just an http request, returning data as json objects. The 403 error indicates that your request was accepted as a valid request, but intentionally rejected by the server for some reason. And according to the docs, the error was because your account is not allowed access to either https or to the type of request.
Their free-tier subscription only includes end-of-day data, which is what you requested, so it wouldn't make sense for that not to be allowed. So, your app is almost certainly making an https call.
I went to the examples at the very beginning of their quick start guide, and chose the end-of-day example to match your app, and clicked on the link. It worked, and gave a bunch of json records. But, the request they made was using 'http' not 'https'.
Changing the requst to 'https' elicited a 403 response with this content (formatted for readability):
{
"error":
{
"code": "https_access_restricted",
"message": "Access Restricted - Your current Subscription Plan does not support HTTPS Encryption."
}
}
At this point we have enough to be almost certain that this is your issue. The final thing is to go look up how to turn https requests off in their class library. To avoid having to go through the code, I checked the help at the bottom of the page one more time, and found this (formatted for readability):
var options = Options.Create(new MarketstackOptions(){
ApiToken = apiKey,
MaxRequestsPerSecond = 3,
Https = true
});
Welp. This should probably be in their first example, since that's what people are most likely to try first, but it's not. So, to stop trying to make http requests, you just need to set the Https option to false in your code. You just need to add that to the options in your code, like so:
var options = Options.Create(new MarketstackOptions(){
ApiToken = "secretTokenHere",
Https = false
});
I will leave the testing to you, but from the browser test, we know that the request should work, unless there's a bug in their library. Given the information that was available, this is almost certainly the issue.
I am looking for a way to call the appropriate method (get, post etc.) on an ApiController class based on the URL and request type etc. without making a http request.
Background: We have an API application with numerous controllers that needs to also accept requests from a remote server. Due to restrictions I cannot control there is no way to open ports between the two servers to allow the remote server to make the request directly so we decided to forward the data using websockets (SignalR). I can send (within reason) whatever information is required.
I have tried the below:
HttpRequestMessage request = new HttpRequestMessage();
var bld = new UriBuilder
{
Port = 123,
Path = "api/v1/search",
Query = "query=search_string"
};
request.RequestUri = bld.Uri;
var httpCfg = AppConfiguration.Get().HttpConfig; //this is the same config that UseWebApi was called with and contains the routes.
var route = httpCfg.Routes.GetRouteData(request);
var controllerSelector = new DefaultHttpControllerSelector(httpCfg);
var descriptor = controllerSelector.SelectController(request);
route contains the controller name (search) but the call to SelectController throws an exception with a 404 response in it (I presume this indicates I am missing something from the fake request). The same URI works when sent as a direct http request so the routes do work as best I can tell.
Is there a better way to do this, or if not what am I missing from the request that is causing the 404?
I am calling an Restful API that expects me to pass a parameter callback(a URL)when doing POST.
The tool that I am using to make the call is RESTSharp. I have written the below code
var client = new RestClient("https://services.mywebsite.com/api/v3/");
client.Authenticator = new HttpBasicAuthenticator("Usernamae", "P2$$w0rd");
var request = new RestRequest("myAction", Method.POST);
request.AddHeader("Accept", "application/json");
request.AddParameter("Id", "sid");
request.AddParameter("callback", "http://localhost"); // ????????
request.RequestFormat = DataFormat.Json;
request.AddFile("file", #"e:\MyDocuemnt.pdf");
client.ExecuteAsync(request, response => {
Console.WriteLine(response.Content);
The line with the parameter callback requires me to pass a url
what should I be passing in here ?
the result is passed back to the callback Url provided, how do I get to see that?
My application is a console application and I want to capture the result here.
Your API is expecting a place to dump the results after it has been processed.
This is what is happening as per my understanding.
You make a call to the API and expects you to provide a callback url
The API returns you a response.
Now the question here is where is my result and if it is sent to the callback url how do I get it.
This is waht you need to do.
You could create a Web API with a POST method that would do the trick for you.
Make sure you are hosting your WebApi which should be accessible by the service which you are calling and expect to send you the result.
public void Post([FromBody]JToken value)
{
var path = HttpContext.Current.ApplicationInstance.Server.MapPath("~/App_Data");
File.WriteAllText(path + #"/WriteJSON" + DateTime.Now.Ticks.ToString() + ".txt", value.ToString());
// write any code that you want to here
}
This should do the trick for you.All i am doing here is writing the response back you may want to do whatever you wish to do with this.
I have the following code.
public T SendUpdateRequest(string url)
{
using (JsonServiceClient client = new JsonServiceClient())
{
T response = client.Put<T>(url);
return response;
}
}
I have similar methods for create and delete requests, calling the JsonServiceClient Post and Delete methods respectively.
When calling my update or create methods, the call to the external API works fine. Delete does not. I can see that the API's delete method does indeed work if I fire a request to it via REST console.
When I compare my non-working delete with the working one's request/response in Fiddler, I can see the main difference is my request is not setting content-type to application/json (all these methods return JSON).
My question is, is it possible (or even necessary) to explicitly set the content-type of my delete request to application/json in order to successfully call my API method?
The ServiceStack clients do not set the content-type header on requests where there is no request body, as the content-type only applies to the body, and is therefore redundant.
This can be seen here in the code that prepares the client request.
if (httpMethod.HasRequestBody())
{
client.ContentType = ContentType;
...
A correctly implemented RESTful service should be happy with a DELETE request without content-type being specified where there is no body.
DELETE /User/123 HTTP/1.1
If the service you are calling is not happy with your request without this type being specified (which is unusual), then you can manually enforce the sending of the type using this filter:
var client = new JsonServiceClient("https://service/");
client.RequestFilter += (httpReq) => {
// Force content type to be sent on all requests
httpReq.ContentType = "application/json";
};
I hope that helps.