I've made a REST API and I'd like to do a post request to one of the endpoints from my ESP8266, but I can't manage to do so.
The code inside the loop so far:
HTTPClient http; //Declare object of class HTTPClient
http.begin("http://localhost:5000/api/users/5b1e82fb8c620238a85646fc/arduinos/5b243dc666c18a2e10eb4097/data");
http.addHeader("Content-Type", "text/plain");
http.addHeader("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjViMWU4MmZiOGM2MjAyMzhhODU2NDZmYyIsImlhdCI6MTUyOTEwMTc5MiwiZXhwIjoxNTI5MTE2MTkyfQ.2O6knqriuFoEW9C2JQKRlM3D0DNnzqC7e7gpidy3pWU");
http.end();
The problem is that I don't know how to set the body of the request.
It should be a json with a single key called "value". For instance:
{
"value":101
}
Anyone knows how to do it? Also it's probable that I should use the ip instead of "localhost".
Thanks in advance.
Use ArduinoJson Library here. Then you can build your HTTP body.
StaticJsonBuffer<300> JSONbuffer; //Declaring static JSON buffer
JsonObject& JSONencoder = JSONbuffer.createObject();
JSONencoder["value"] = value_var;
char JSONmessageBuffer[300];
JSONencoder.prettyPrintTo(JSONmessageBuffer, sizeof(JSONmessageBuffer));
HTTPClient http; //Declare object of class HTTPClient
http.begin("API end point here"); //Specify request destination
http.addHeader("Content-Type", "application/json"); //Specify content-type header
int httpCode = http.POST(JSONmessageBuffer); //Send the request
String payload = http.getString(); //Get the response payload
Then use the above sample code to encapsulate JSON and send it to the API endpoint.
Related
I am very new to programming with ESP8266 and can't get this to work.
I am successfully connected to the internet.
With the <ESP8266HTTPClient.h> I am writing the following code:
void loop() {
if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
HTTPClient http; //Declare object of class HTTPClient
http.begin("https://api.entur.io/journey-planner/v2/graphql"); //Specify request destination
http.addHeader("Content-Type", "application/json"); //Specify content-type header
http.addHeader("ET-Client-Name", "student-bussAPI"); //Identification requested by the API
int httpCode = http.POST("{\"query\":\"{authorities{id}}\"}"); //Send the request
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
http.end(); //Close connection
} else {
Serial.println("Error in WiFi connection");
}
delay(30000); //Send a request every 30 seconds
}
the code runs with serial output -1
I have tested the query request on postman, and it worked fine there.
The "-1" you are getting is caused by the attempt to establish a connection to a strictly HTTPS service via HTTP.
As the code examples in the ESP8266HttpClient library explain, "httpCode will be negative on error" - what you are seeing is the printing of a http status code of -1.
The easiest way to achieve what you are trying to do here (Query a HTTPS API via the ESP8266httpClient library) would be to connect to it using the current SHA-1 fingerprint of the certificate used by the service as a second parameter of your call to "http.begin".
Example to answer your specific question:
HTTPClient http; //Declare object of class HTTPClient
const char* host = "https://api.entur.io/journey-planner/v2/graphql";
const char* fingerprint ="Current sha-1 fingerprint goes here";
http.begin(host, fingerprint); //Specify request destination and fingerprint for cert to make it do HTTPS
http.addHeader("Content-Type", "application/graphql"); //Content type here is important; Its not JSON
http.addHeader("ET-Client-Name", "Esp8266-BitBrb");
I should also mention that the specific API you are using here has a strict check on content type, so you should change your header to match the data type the API accepts, "application/graphql", or else you'll have trouble :)
Incidentally, i have the full code from a project i did last year with the same service you are using (Hi, fellow Norwegian and EnTur user) available here: https://www.bitbrb.com/electronics/graphql-querying-a-bus
I see they got a new certificate earlier this year, other than that you should be able to cut and paste.
good luck :)
I am quite new in Spring Cloud Feign and trying to send HTTP header which is required by service provider. Here is the code snippet
#FeignClient(name = "authentication", url = "http://localhost:3000/api")
public interface AuthenticationService {
#PostMapping(value = "/login")
JsonNode login(#RequestHeader("Origin") String origin, #RequestBody LoginParams parameters);
}
When I try to send Origin header then server does not receive this header. But other headers like referer or x-access-token are received at server successfully.
I have also tried using RequestInterceptor and was not successful to send Origin as header.
#Component
public class HeaderInterceptor implements RequestInterceptor {
#Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.removeHeader("origin");
requestTemplate.header("origin", "http://amjad.localhost:3000/");
}
}
Any hint or help would be much appreciated.
cheers!
I had similar issue with OpenFeign. "Origin" header was blocked by defult, because it was using old Java http client.
After change to OkHttp Client, "Origin" was sent.
I am creating a proxy using middleware in ASP.NET Core 2.1 that makes 3rd party API (OData endpoint) call to
Get data
Do some changes
Send response to Response.Body
I took a reference from here
Below is the code snippet that works fine as whatever response I am getting from API, I am sending it further
using (var responseMessage = await _httpClient.SendAsync(targetRequestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
{
context.Response.StatusCode = (int)responseMessage.StatusCode;
CopyFromTargetResponseHeaders(context, responseMessage);
await responseMessage.Content.CopyToAsync(context.Response.Body);
}
However, If I modify the response here, for example, like this, it does not work and it shows blank page without any error.
using (var responseMessage = await _httpClient.SendAsync(targetRequestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
{
context.Response.StatusCode = (int)responseMessage.StatusCode;
CopyFromTargetResponseHeaders(context, responseMessage);
var output = new StringContent("some sample string or may be JSON", Encoding.UTF8, "application/json");
await output.CopyToAsync(context.Response.Body);
}
It looks like we are not allowed to make any change in the response received from API call. Can anyone please tell me how can send modified content back to Response.Body?
I am able to solve the problem by updating "Content-Length" response header before rendering modified response to context.Response.Body something like this:
context.Response.Headers.Remove("Content-Length");
context.Response.Headers.Add("Content-Length", modifiedResponseStream.Length.ToString());
You might run into a System.InvalidOperationException: Response Content-Length mismatch: too few bytes written or similar exception (which you should see in the Output window). So do not use the Content-Length and maybe Content-Type headers from the response, because they probably don't match with the Content-Length and Content-Type of your modified content, e.g.:
private void CopyFromTargetResponseHeaders(HttpContext context, HttpResponseMessage responseMessage)
{
...
foreach (var header in responseMessage.Content.Headers)
{
// do not use the content headers from the response because the content will be modified
// context.Response.Headers[header.Key] = header.Value.ToArray();
}
...
}
I'm trying to process a server response which is GZIP'd. The response comes with a header
Content-Type: application/x-gzip
but does not have header
Content-Encoding: gzip
If I add that header using a proxy, the response gets parsed just fine.
I don't have any control over the server, so I can't add the header.
Can I force Retrofit to treat it as GZIP content? Is there a better way?
The URL for the server is:
http://crowdtorch.cms.s3.amazonaws.com/4474/Updates/update-1.xml
I figured it out. The idea is to add a custom interceptor which will take the not-yet-unzipped response, and unzip it 'manually' - do the same thing that OkHttp would do automatically based on Content-Encoding header, but without requiring that header.
is like dis:
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.addInterceptor(new UnzippingInterceptor());
OkHttpClient client = clientBuilder.build();
And the Interceptor is like dis:
private class UnzippingInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
return unzip(response);
}
}
And the unzip function is like dis:
// copied from okhttp3.internal.http.HttpEngine (because is private)
private Response unzip(final Response response) throws IOException {
if (response.body() == null) {
return response;
}
GzipSource responseBody = new GzipSource(response.body().source());
Headers strippedHeaders = response.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
return response.newBuilder()
.headers(strippedHeaders)
.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)))
.build();
}
There is a better way than reinventing the wheel. Just add the Content-Encoding header yourself.
.addNetworkInterceptor((Interceptor.Chain chain) -> {
Request req = chain.request();
Headers.Builder headersBuilder = req.headers().newBuilder();
String credential = Credentials.basic(...);
headersBuilder.set("Authorization", credential);
Response res = chain.proceed(req.newBuilder().headers(headersBuilder.build()).build());
return res.newBuilder()
.header("Content-Encoding", "gzip")
.header("Content-Type", ""application/json")
.build();
})
In fact, your code is a classic example of the evils of using internal code (like com.sun packages from the JDK). RealResponseBody doesn't have that constructor anymore.
I am using Restlet2.3 to run REST API test automation.
The new feature has a customer HTTP header to pass a token to the service.
Form headers = (Form)resource.getRequestAttributes().get("org.restlet.http.headers");
if (headers == null) {
headers = new Form();
resource.getRequestAttributes().put("org.restlet.http.headers", headers);
}
...
headers.add(key, value);
The code works. Now, the customer HTTP header is defined as "Authorization". The above code seems not passing the header properly. And this is not challengeScheme involved.
I tested this scenario on SoapUI and Postman. Both work.
Anyone knows that restlet support this?
In fact, you can't override standard headers like Authorization with Restlet when doing a request.
If you want to provide a security token, you could use this approach:
String pAccessToken = "some token";
ChallengeResponse challengeResponse = new ChallengeResponse(
new ChallengeScheme("", ""));
challengeResponse.setRawValue(pAccessToken);
clientResource.setChallengeResponse(challengeResponse);
This way you'll have only the token in the Authorization header (with a space at the beginning - so don't forget to trim the value).