I'm trying to call a Tableau endpoint to get the list of project.
It is in 2 steps:
Call the signIn endpoint to get a token that allow to call others endpoint
Call the list projects endpoint with my signed In token
By using insomnia, this is working like a charm, but in csharp code, the first step is working well, but the second always returning me a 401 error.
Tableau list projects documentation
public async Task<string> ListProjectAsync()
{
var signIn = await SignInAsync(); // Working
var endPoint = $"https://myTableauSite.com/api/3.17/sites/{signIn.SiteId}/projects";
var acceptedCodes = new List<HttpStatusCode>();
acceptedCodes.Add(HttpStatusCode.OK);
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Tableau-Auth", signIn.Token);
HttpResponseMessage response = await client.GetAsync(endPoint); // 401
response.EnsureSuccessStatusCode();
string responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
Edit: The problem was from the JWT generated token that had a missing permission, my bad
The only difference I could find between your code's request and insomnia is that you forgot to set the content-type
public async Task<string> ListProjectAsync()
{
var signIn = await SignInAsync(); // Working
var endPoint = $"https://myTableauSite.com/api/3.17/sites/{signIn.SiteId}/projects";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Content-Type", "application/xml");
client.DefaultRequestHeaders.Add("X-Tableau-Auth", signIn.Token);
HttpResponseMessage response = await client.GetAsync(endPoint); // Should be working
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
Related
I wrote a function which consumes Web API. This function works great for GET requests. However, I need to get some other resources from API which, according to API provider's docs, requires POST method. So I've simply changed HttpMethod from Get to HttpMethod.Post. When I call the API then I get Error 400 Bad Request.
CallAPI
private static async Task<T> CallAPI<T>(string endpoint, string accessToken)
{
var request = new HttpRequestMessage(HttpMethod.Post,
new Uri(ApiUri, endpoint));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var _httpClient = new HttpClient();
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var responseStream = await response.Content.ReadAsStreamAsync();
var responseObject = await JsonSerializer.DeserializeAsync<T>(responseStream);
return responseObject;
}
I call this API:
var result = await CallAPI<SomeDataModel>("cars/locations", accessToken);
Don't know where is a problem. It works great for GET as I said. Moreover, I don't understand why there's a need to use POST instead of GETto get data. I think it's against REST best-practices. According to provider's API docs, I don't need to attach any parameters to POST request, it's just raw endpoint. Anyways, I need to use POST here to get data.
I'm trying to access/call methods in a REST API with a token from c#/.net- but I can't get any response back. I have googlet a lot - but without any success :-( I am new to call methods via a REST API.
I have an endpoint and a token which I need to use for communicating with a REST API. And I need to GET, POST, PUT and DELETE data on the server via those methods
The output from the API is in JSON format.
Maybe it is simple - but I don't know howto do it.
Any help is appreciated.
I have tried the following solution - but with no success :-(
private static async void DoIt()
{
using (var stringContent = new StringContent("{ \"firstName\": \"Andy\" }", System.Text.Encoding.UTF8, "application/json"))
using (var client = new HttpClient())
{
try
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token);
// 1. Consume the POST command
var response = await client.PostAsync(endpoint, stringContent);
var result = await response.Content.ReadAsStringAsync();
//Console.WriteLine("Result from POST command: " + result);
// 2. Consume the GET command
response = await client.GetAsync(endpoint);
if (response.IsSuccessStatusCode)
{
var id = await response.Content.ReadAsStringAsync();
//Console.WriteLine("Result from GET command: " + result);
}
}
catch (Exception ex)
{
//Console.ForegroundColor = ConsoleColor.Red;
//Console.WriteLine(ex.Message);
//Console.ResetColor();
}
}
}
In your code you initialize AuthenticationHeaderValue with "Basic", which means Basic authentication based on username and password. If you have a token, you do it with:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ACCESS_TOKEN);
replace ACCESS_TOKEN with the token you have.
This is the most probable solution, but I can only guess here, as I don't know the API you're trying to access. If it still doesn't work, try ommiting "Bearer".
Reference
Im making some automatic surveillance for an Rest API im running and i need to retrieve the response body from the HttpResponseMessage object.
Im using Flurl Http: https://flurl.dev/docs/fluent-http/
I know how to retrieve the responsebody by adding ".RecieveSomeForm()" at the end of the http request, but i also need to get the response headers, as the error code from the Rest API is sent back as a header. My problem is that - to my knowledge and what i tried - its only the HttpResponseMessage object that i can retrieve the headers from. So the question is:
How do i get the responsebody out of the HttpResponseMessage while still being able to retrieve the headers for error logging?
using (var cli = new FlurlClient(URL).EnableCookies())
{
//get response body - var is set to string and has only response body
var AsyncResponse = await cli.WithHeader("some header").Request("some end point").AllowAnyHttpStatus().PostJsonAsync(some body).ReceiveString();
Console.WriteLine(AsyncResponse);
//get headers - var is set to HttpResponseMessage
var AsyncResponse = await cli.WithHeader("some header").Request("some end point").AllowAnyHttpStatus().PostJsonAsync(some body);
Console.WriteLine(AsyncResponse.Headers);
}
If I've understood correctly, you want Headers + Response body from a HTTP response.
var response = await cli.WithHeader("some header").Request("some end point").AllowAnyHttpStatus().PostJsonAsync("some body");
var headers = response.Headers; //do your stuff
var responseBody = response.Content != null ? await response.Content.ReadAsStringAsync() : null;
Another option which I personally don't like:
var responseTask = cli.WithHeader("some header", "haha").Request("some end point").AllowAnyHttpStatus().PostJsonAsync("some body");
var headers = (await responseTask).Headers; //do your stuff
var responseBody = await responseTask.ReceiveString();
Unfortunately, Flurl's extension methods can be used on Task, not on HttpResponseMessage. (that's why you have to avoid awaiting in the first line of code)
I am trying to get some information from an API using GetAsync, but I am getting a status code of 403 even after adding the OAuth authorization header with the token provided for me. Is there something else I need to do, or is my token bad?
class TestAPI
{
static void Main()
{
var client = new HttpClient();
client.BaseAddress = new Uri(BASE_ADDRESS_FOR_TESTING);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("OAuth", TOKEN);
HttpResponseMessage response = await client.GetAsync("WebApi/CaseLogs/v10/Search?DateFrom=04-05-2012");
if (response.IsSuccessStatusCode)
{
result = await response.Content.ReadAsStringAsync();
}
else
{
Console.WriteLine((int) response.StatusCode); // prints "403"
}
}
}
Your HttpClient looks fine to me. I think your Token is bad.
The 403 Error also supports this theory.
403
FORBIDDEN The server understood the
request but refuses to authorize it.
A server that wishes to make public why the request has been forbidden
can describe that reason in the response payload (if any).
https://httpstatuses.com/403
You should also print your response message.
using ( HttpResponseMessage response = await client.GetAsync("WebApi/CaseLogs/v10/Search?DateFrom=04-05-2012"))
using (HttpContent content = response.Content)
{
string result = await content.ReadAsStringAsync();
Console.WriteLine(result);
}
Try this code to see if you get more information in the response content.
Hope this helps.
Used the Flurl to Get response from API.
var response = await url.WithClient(fc)
.WithHeader("Authorization", requestDto.ApiKey)
.GetJsonAsync<T>();
dynamic httpResponse = response.Result;
But I cant able to access httpResponse.Headers
How to access response headers while using GetJsonAsync .
You can't get a header from GetJsonAsync<T> because it returns Task<T> instead of raw response. You can call GetAsync and deserialize your payload at next step:
HttpResponseMessage response = await url.GetAsync();
HttpResponseHeaders headers = response.Headers;
FooPayload payload = await response.ReadFromJsonAsync<FooPayload>();
ReadFromJsonAsync is an extention method:
public static async Task<TBody> ReadFromJsonAsync<TBody>(this HttpResponseMessage response)
{
if (response.Content == null) return default(TBody);
string content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TBody>(content);
}
P.S. This is why I prefer and recommend to use raw HttpClient instead of any third-party high-level client like RestSharp or Flurl.
You could also await for the HttpResponseMessage, pick off the .Headers object, then send the completed task to ReceiveJson<T> for deserialization. Here's how to do it without an extension method:
var task = url.GetAsync();
HttpResponseMessage response = await task;
HttpResponseHeaders headers = response.Headers;
//Get what I need now from headers, .ReceiveJson<T>() will dispose
//response object above.
T obj = await task.ReceiveJson<T>();