While I've been developing in Dynamics for awhile, I have never had to do an external call to an API before.
I'm not sure where to start. Any help in pointing me in the right direction would be very helpful.
The Api in question is located here:
http://apidocs.assess.com/
There are examples within there that show what needs to get passed to the url (https://app.fasttestweb.com/FastTest/api/swagger.json)
But in all honesty, this is my first attempt at this and I'm overwhelmed with the information I've been finding, and having trouble parsing through what needs to be done for this.
Step 1, of course is to generate an auth token from the site.
This needs to be passed in this formation (I assume that is JSON).
But I'm having trouble figuring out how to even do that part, or what the code should even look like. If anyone has an example of something they've done, or can point me to a link/video that walks through this, that would be awesome.
Note, I do have Newtonsoft.Json installed in Visual Studio, but I'm having trouble finding good examples on how to actually pass the information back and forth.
Thank you in advance.
How to call an API in rest is a really common practice as a developer since this is common practice to expose data, i highly recommend that you read up on the subject, there are alot of good resources out there, this site is one and youtube is another, did a quick search and found alot about it: https://www.youtube.com/results?search_query=intro+to+rest+c%23
To the problem at hand:
The swagger documentation tells you all you need to know to call the service your after,
Take the auth service for example, first of we need to know which method the service uses, in this case it is post.
Now we need to know which address we can call the service. Specified in the docs as: https://app.fasttestweb.com/FastTest/api/auth/simple
What are we sending:
{
"username": "string",
"pwd": "string",
"apiKey": "string",
"timeSent": 0,
"tokenTTL": 0
}
if you switch to model you can see the description of the parameters. You can even test this out directly in the page by editing the editable box with the values you were given and pressing "try it out!" in the bottom of the endpoint specification.
What response are we getting:
{
"apiToken": "string",
"timeGenerated": 0,
"ttl": 0
}
To call it, there are many ways to do this, i like to make separate objects/dto's of what im sending and recieving and then serialize/deserialize them from and to that object. Since you already have json.net here is how you do serialize.
You can specify the specific json names so it matches with the schema with an attribute
or define a strategy.
When you get the json back from the service you will have to deserialize it.
So your body obj would look like this for example
public class AuthBody
{
[JsonProperty("username")]
public string UserName { get; set; }
[JsonProperty("pwd")]
public string Password { get; set; }
[JsonProperty("apiKey")]
public string ApiKey { get; set; }
[JsonProperty("timeSent")]
public int TimeSent { get; set; }
[JsonProperty("tokenTTL")]
public int TokenTimeToLive { get; set; }
}
Just setup the response in similar fashion.
I like to use a lib called RestSharp to call rest services, its available on nuget.
Here is a very basic code example (not tested):
var body = new AuthBody()
{
UserName = "value",
Password = "value",
ApiKey = "value",
TimeSent = 123,
TokenTimeToLive = 10000
};
var json = JsonConvert.SerializeObject(body);
var client = new RestClient("https://app.fasttestweb.com/FastTest/api");
var request = new RestRequest("auth/simple", Method.POST, DataFormat.Json);
request.AddParameter("application/json", json, ParameterType.RequestBody);
var jsonResponse = client.Execute(request);
AuthResponse authResponse = JsonConvert.DeserializeObject<AuthResponse>(jsonResponse.Content);
You can also set the default serializer of restsharp to json.net if you want, then you can set the body with addJsonBody instead of the parameter and you dont have to serialize your object yourself, more info is available on RestSharp.
if you dont want to use RestSharp, the normal client is called HttpClient instead of RestClient, if you want to google it.
Hope it helps.
Related
TLDR Using CDKTF for C#, how do I use the outputContent of the ResourceGroupTemplateDeployment resource in downstream resources? The JSON structure is
{
apiKey: {
value: <the value>
},
queryKey: {
value: <the query key value>
}
}
So I would like to be able to pass this value to say, a Function App's config, but any attempts to get apiKey in C# lead to an error because C# sees the value as a Token and not the JSON object.
I am currently using CDKTF with C# to build out infrastructure. I am using a resource ResourceGroupTemplateDeployment which returns an Output object which is a string that is actually a JSON object. I would like to retrieve two values from this to use in downstream resources. In HCL this is trivial to do, I would just do something like sensitive(jsondecode(azurerm_resource_group_template_deployment.service.output_content).myKey.value) and that would get me what I need. In CDKTF though this is not so straightforward.
While running the initial synth (building and converting C# into json) the Output value is actually a TFToken. This means that it's essentially a placeholder for the real value which is currently unknown because Terraform hasn't actually run the plan/apply. more info on that here.
So it returns a string when the code is first run, but when terraform plan/apply runs it has the real values. I need the values from the JSON object to assign them to the downstream resources, how can I possibly do this if they're undefined when the code is building? Here is my code:
ResourceGroupTemplateDeployment searchService = new ResourceGroupTemplateDeployment(this, "search-service", new ResourceGroupTemplateDeploymentConfig
{
Name = $"{searchName}-{suffix.Result}",
ResourceGroupName = rg.Name,
DeploymentMode = "Incremental",
ParametersContent = JsonSerializer.Serialize(new Dictionary<string, Dictionary<string,string>>{
{"searchServices_dev_request_search_name", new Dictionary<string, string>{
{ "value", $"{searchName}-{suffix.Result}" }
}
}
}),
TemplateContent = template,
});
SearchTemplateOutput resultObj = JsonSerializer.Deserialize<SearchTemplateOutput>((searchService.OutputContent));
apiKey = resultObj.apiKey;
class SearchTemplateOutput {
public string apiKey {get; set;}
public string queryKey {get; set;}
}
The above code does not work and gets an error Unhandled exception. System.Text.Json.JsonException: '$' is an invalid start of a value. because the value is a Token, it's not an actual JSON object yet... but it will be :/
I also tried adding Token.AsString
SearchTemplateOutput resultObj = JsonSerializer.Deserialize<SearchTemplateOutput>(Token.AsString(searchService.OutputContent));
but the result is the same. It blows up trying to deserialize the result because it's a Token, not the actual values that I need to reference later.
I'm not sure how to handle this, the documentation just gives incredibly simple examples where you're getting something simple returned to you and you use the entire object that's returned, but in this situation it's a JSON object with multiple values that gets returned, so I am at a loss for how to access those values.
The answer to my question was found in the AWS documentation which was linked to from the TF documentation. Essentially it said that you can't manipulate JSON lists/strings, and so the solution was to just create the object using the resource group template (since there is an outstanding bug > 1 year in Azure where their API doesn't conform to their own standard which breaks the search service through terraform if using the free tier) and then after it is created, use the associated data object to get the values.
For what it's worth, here is the final setup I have done to be able to get the values safely using C#
DataAzurermSearchService searchSvcData = new DataAzurermSearchService(this, "search-service-data", new DataAzurermSearchServiceConfig
{
Name = searchService.Name,
ResourceGroupName = rg.Name
});
apiKey = searchSvcData.PrimaryKey;
queryKey = searchSvcData.QueryKeys.Get(0).GetStringAttribute("key");
This solution might be obvious to someone more well versed with C#, but it took me some time to figure it out. Hopefully it helps someone else someday
I'm having trouble with passing in parameters to a get request. This request is intended to return a list of warehouses after the user entered some search parameters such as Date, State, ZIP and/or warehouse number, which is the only mandatory field. So when the search button is pressed the query is executed, but im getting this error:
2021-04-19 15:49:00 +0000
2021-11-02 13:06:44.670511-0600 WAREHOUSE_IOS-Master[3142:186324] GET method must not have a body
2021-11-02 13:06:44.670799-0600 WAREHOUSE_iOS-Master[3142:186324] Task <C7839029-C527-490E-8747-137012285F14>.<3> finished with error [-1103] Error Domain=NSURLErrorDomain Code=-1103 "resource exceeds maximum size" UserInfo={NSLocalizedDescription=resource exceeds maximum size,
error: invalidResponse
Okay so what im doing is passing a body to the get request that includes the search parameters as such:
struct WarehouseBody : Codable {
let dateRegistration : String?
let state : String?
let zip : String?
let warehouseNumber : String
}
and I'm expecting a response of this type:
struct WareHouseResponse: Codable {
let status: String?
let code: Int?
let responseCode, message: String?
let error: Bool?
let errorMessage: String?
let result: Result?
enum CodingKeys: String, CodingKey {
case status = "Status"
case code = "Code"
case responseCode = "ResponseCode"
case message = "Message"
case error = "Error"
case errorMessage = "ErrorMessage"
case result = "Result"
}
}
but according to what I've reading on other posts this is not the correct way of using a get request, but I really really need to do some testing. Is there a way that I can achieve this without needing to alter the backend? Just to mention that I ´m also the developer of the backend (c# using .net framework and dapper)so if the easiest way is to achieve this is by altering it I can also do that. Any ideas are very much appreciated.
On the backend I was thinking of implementing a post Request that sends the search parameters to the server and then a get request that pulls out the requested information, but I don't know if that's the correct approach. But this not feasible at the moment because the Web API are already publish and I cannot re publish with the changes at the moment, and is really urgent to test the response so that's why I would like to know if all this can be done from the front end first. Thank you very much for all the help!
Thank you very much for your help!
EDIT: Also I forgot to mention that the api has been previously tested on POSTMAN and is working perfectly.
Since iOS 13. you cannot pass in parameters to a GET request. There’s no easy way around this. You need to change your request from a GET to a POST on the backend. In my case, this was an easy task because I had access to the API source— but, if you don’t, just ask the backend team to change it, and pass in the parameters as in any other POST request. That should work.
I'm trying to write a webhook for Mailchimp events using API version three and I'm struggling a bit due to their lack of a library, documentation, and basic examples, but also my lack of experience.
I know we should secure the webhook by putting a secret in the URL, that's fine. By the way, MailChimp doesn't allow configuration of basic access authentication in their portal.
They say "While we do send HTTP POST for actual data, our webhook validator will only send HTTP GET requests. You'll need to allow both in order for your webhook to function properly." Ok, I guess I can use Request.HttpMethod to return a success status code if it's a GET and process some data if it's a POST.
Not sure how to pick stuff out of the request though, and ideally don't want to write heaps of classes and properties to cover all the event types, C# being statically typed, although I guess the dynamic keyword is also an option.
Do I need to deserialise JSON? I've only written one webhook before for another API with the help of a library, you could construct an API event using either a string, stream, or textreader, which came from the request. The library made everything very simple.
For reference, there's also this question which shows how to get some data using PHP: How to pass email address to webhook from mailchimp
The data that gets posted looks like this (supposedly, there doesn't seem to be any documentation for V3):
"type": "unsubscribe",
"fired_at": "2009-03-26 21:40:57",
"data[action]": "unsub",
"data[reason]": "manual",
"data[id]": "8a25ff1d98",
"data[list_id]": "a6b5da1054",
"data[email]": "api+unsub#mailchimp.com",
"data[email_type]": "html",
"data[merges][EMAIL]": "api+unsub#mailchimp.com",
"data[merges][FNAME]": "MailChimp",
"data[merges][LNAME]": "API",
"data[merges][INTERESTS]": "Group1,Group2",
"data[ip_opt]": "10.20.10.30",
"data[campaign_id]": "cb398d21d2",
"data[reason]": "hard"
I just basically need to get this data into variables so I can sync it with my database.
Here's my (skeleton) controller so far:
[Route("mailchimp/newsletter-webhook/super-secret-key-goes-here")]
public HttpStatusCodeResult ChargeBeeWebhook()
{
return new HttpStatusCodeResult(200);
}
Assuming you've already set up your MailChimp Webhooks as described here, you can get the posted data using Request.Form syntax. Using the example posted data from the question, here's how your controller code should look like:
[AllowAnonymous]
public void ChargeBeeWebhook()
{
// type variable will be "unsubscribe"
string type = Request.Form["type"];
// action variable will be "unsub"
string action = Request.Form["data[action]"];
// reason variable will be "manual"
string reason = Request.Form["data[reason]"];
// ...
// ...
// ... do the same with the rest of the posted variables
// ...
// sync the posted data above with your database
// ...
// ...
}
I have been reading around building an action method in my Web Api to allow the posting of images, which would be saved on the server and related to a Contact object via a field imageURL.
I have found a few examples online of how to set this up, and am wanting to test them. I currently have:
public Task<HttpResponseMessage> PostFile()
{
HttpRequestMessage request = this.Request;
if (!request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = System.Web.HttpContext.Current.Server.MapPath("~/Content/images");
var provider = new MultipartFormDataStreamProvider(root);
var task = request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(o =>
{
string file1 = provider.BodyPartFileNames.First().Value;
//Use file name to update ImageURL of contact
return new HttpResponseMessage()
{
Content = new StringContent("File uploaded.")
};
}
);
return task;
}
from How To Accept a File POST, and whilst I understand the flow I want to test it properly.
What would an example of a client call be to this API method, where I can include the contactid as a header?
I need to understand this properly to test this code sample so I can start understanding this more, but I'm really new to this area. I have kind of a chicken and egg scenario where I understand little about posting and receiving images and need a start point.
Thanks.
You can use a small MVC or ASP application (you only need one page) where you can use some JS plugins to post files to your controller.
Plugins: jQueryFileUpload or DropzoneJS. The last one is more easy to integrate. Both plugins has support for sending additional data.
If I have a complex object that is been sent as an API request (for example Order below), should I include all the properties when generating the signature or should I use just a subset?
I am asking because I am unclear and from looking at other API's the requests parameters are flat and simple
public class Order
{
public string Id { get; set; }
public string ClientIdentifier { get; set; }
public IEnumerable<OrderItems> OrderItems { get; set; }
public long timestamp { get; set; }
public string signature { get; set; }
}
public class OrderItems
{
public string ItemId { get; set; }
public string Name { get; set; }
public IEnumerable<decimal> PriceBands { get; set; }pes
more types
}
and so on ....
You first need to understand what the signing of the message prevents to understand what data should be included in the request. Here's a list of the 2 main things that signing the requests block attackers from being able to do.
With a signed request the password is kept safe and an attacker cannot use the information in the query to sign another request. This is helpful if the attacker can see the request being sent to the server.
The attacker cannot modify any data in the request that has been used to generate the signature without invalidating the signature, causing the request to be refused by the server.
Number 2 has a catch to it. It only helps protect the data that is part of the signature. If you leave any data out an attacker could change that data and send a different message than the message you sent. This is why when signing a request all of the request data needs to be included: The full URI including the domain, headers, querystring parameters, and any posted data such as XML or JSON.
As hinted by naveen in the comment above, your question does not seem to be a an OAuth question directly:
Looking at the (quite good) explanation of the OAuth flow at http://hueniverse.com/oauth/guide/authentication/ leads to the conclusion that all parameters in an OAuth request need to be used in signing the request because the server will also take all parameters (by definition) to validate the signature, so my suggestion is to use all parameters for signing, too ;)
But (as a side note):
Your code shows a complex data strutcture which should be submitted, so this raises some more questions: how do you encode the data to be transferable via HTTP? How does the server implementation look like (is it your own implementation or a given service)?
Assuming that you serialize the data to XML or JSON to be used as a request parameter, you'll get "just a string" for the data. This data - used as a request parameter - will completely be used for signing as mentioned above.
I'd also suggest using an Open-Source OAuth client implementation. A good place to start looking for one is the Twitter Client Library page at https://dev.twitter.com/docs/twitter-libraries#dotnet because Twitter uses OAuth for 3rd-party access to its API and the libraries (OAuth components like Hammock) are stable.
As it was already pointed out you need to figure out what attacks you want to prevent.
Usual approach to case when data you are submitting is sensitive is to use HTTPS (SSL) to communicate with the server. In this case you don't need to encrypt/sign data itself, any plain protocol including sending JSON is OK.
If you want to prevent unknown clients to post the data use mutual SSL which will allow you to limit what client can talk to server.
If you want to verify data is not tampered with over HTTP - sign whole data block... But it is much harder to implement correctly that using existing SSL connection. Check out http://blogs.msdn.com/b/ericlippert/archive/2011/09/27/keep-it-secret-keep-it-safe.aspx