I'm trying to perform a request using Retrofit but I'm getting 404 error whereas it is working using Postman:
Authorization header with value "key=123456789"
Content-Type header with value application/json
and in the body:
{"notification": {"title":"Title","text":"Hello"},"to":"1234"}
The response will be like:
{ "multicast_id": 108,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{ "message_id": "1:08" }
]
}
I have this Retrofit 2 code:
public interface FcmApi {
#POST("/")
#Headers({"Content-Type: application/json", "Authorization: key=123456789"})
Observable<MyResponse> send(#Body String body);
}
MyResponse class
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyResponse {
public int success;
}
and a test:
String json = "{\"notification\": " +
"{\"title\":\"Title\",\"text\":\"Hello\"}," +
"\"to\":\"1234\"}";
api.send(json);
But I get 404 error. Using Postman works properly with the same example.
Seems like you're using key=123456789. You should be using the server key from Firebase Console. Also "to":"1234" should be the real Firebase Registration Id from your device.
Related
When attempting to programmatically add/update a function key, I receive the following error:
StatusCode: 401, ReasonPhrase: 'Unauthorized'
Code:
Executing the following code results in the error described above.
static void FunctionKey(string resourceGroupName, string functionAppName, string functionName, NameValuePair kv)
{
var resource = $"subscriptions/{SubscriptionId.Value}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{functionAppName}/functions/{functionName}/keys/{kv.Name}?api-version=2022-03-01";
var httpClient = new HttpClient() { BaseAddress = new Uri("https://management.azure.com/") };
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken.Value);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var json = #"{
""Properties"": {
""Name"": ""ApiKey"",
""Value"": ""some_value""
}
}";
using (var content = new StringContent(json, Encoding.UTF8, "application/json"))
{
var response = httpClient.PostAsync(resource, content).Result;
if (!response.IsSuccessStatusCode)
throw new Exception($"Error: Failed to register function key for {functionName}");
}
}
Research:
I was successful when performing this task in the the documentation emulator.
I tried to reproduce the same in my environment via Postman and got below results:
When I ran the below query without including bearer token, I got same error with 401 Unauthorized like below:
PUT https://management.azure.com/subscriptions/<subID>/resourceGroups/<rgname>/providers/Microsoft.Web/sites/<funcappname>/functions/<funcname>/keys/<keyname>?api-version=2022-03-01
{
"Properties":
{
"Name": "keyname",
"Value": "xxxxxxxxxxxx"
}
}
Response:
After passing the token, I'm able to create function key successfully like below:
When I checked the same portal, srikey appeared under function keys like below:
In your case, you are using httpClient.PostAsync which means
POST method.
When I used POST method for below query, I too got 404 Not found error like below:
POST https://management.azure.com/subscriptions/<subID>/resourceGroups/<rgname>/providers/Microsoft.Web/sites/<funcappname>/functions/<funcname>/keys/<keyname>?api-version=2022-03-01
{
"Properties":
{
"Name": "keyname",
"Value": "xxxxxxxxxxxx"
}
}
Response:
To resolve the error, make sure to use PUT method by changing httpClient.PostAsync method to httpClient.PutAsync method.
Reference:
HttpClient.PutAsync Method (System.Net.Http) | Microsoft
So, I am using Amazon Alexa Reminders API as shown here.
Here is my method for sending requests to API:
public static void sendReminder(String accessToken, String reminderText, long offsetInSec) {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost("https://api.amazonalexa.com/v1/alerts/reminders");
post.addHeader("Authorization", "Bearer " + accessToken);
post.addHeader("Content-Type", "application/json");
TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());
String jsonContent = "{ \"requestTime\" : \"" + nowAsISO + "\", \"trigger\": { \"type\" : \"SCHEDULED_RELATIVE\", \"offsetInSeconds\" : \"" + offsetInSec + "\" }, \"alertInfo\": { \"spokenInfo\": { \"content\": [{ \"locale\": \"en-US\", \"text\": \"" + reminderText + "\" }] } }, \"pushNotification\" : { \"status\" : \"ENABLED\" } }";
HttpEntity entity = null;
try {
byte[] bytes = jsonContent.getBytes("UTF-8");
entity = new ByteArrayEntity(bytes);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
post.setEntity(entity);
try {
CloseableHttpResponse response = client.execute(post);
System.out.println(response);
} catch (IOException e) {
e.printStackTrace();
}
}
And I execute it like this:
RemindersToolkit.sendReminder(session.getUser().getAccessToken(), "text", 1);
Skill also has permission for reminders:
But when the method is executed, I get the following response:
HttpResponseProxy{HTTP/1.1 401 Unauthorized [Content-Type: application/json, Connection: keep-alive, Server: Server, Date: Tue, 22 Jan 2019 00:21:21 GMT, Vary: Accept-Encoding,User-Agent, x-amz-rid: 8YMCM10GKVGTT71JQH3N, X-Cache: Error from cloudfront, Via: 1.1 05a90e634e0872685ad69ee9a4e0eba5.cloudfront.net (CloudFront), X-Amz-Cf-Id: J5CtMnkUTv1hd6p-7-tob7mCb-4DM7y_LxhEiMLt5x3qEqmzhwbx_Q==] org.apache.http.client.entity.DecompressingEntity#6df97b55}
According to Amazon on this page, 401 UNAUTHORIZED means Token is valid but does not have appropriate permissions.
Maybe some of you guys had the same problem or could help me figure out how to solve mine?
Thanks
Got it worked, as pointed out in this answer, granting permission in the skill is not enough, the end user using that skill also has to grant the permission. Ask the user for the permission through permission card when encountered with the unauthorized response.
The issue was that I was using the old Alexa SDK.
I had to download current version of the SDK and there is a different key (not accessToken I've used), which can be obtained directly from the Intent object and can then be used to send requests
I am new to developing Alexa skills so I am using a sample I found on the web as a C# endpoint hosted on Azure. It works correctly with the Alexa console but when I try to test the same endpoint with the Postman app, I get a 400 error.
When I use the Alexa console, it displays the JSON input that it sends to the endpoint and the JSON output that it receives from the endpoint. If I copy the JSON input and paste it into Postman and send it to the same endpoint, I get a 400 error. Obviously, I am missing something.
The following are my two source files and the JSON input.
RollTheDice.cs
public static class RollTheDice
{
[FunctionName("RollTheDice")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
var speechlet = new RollTheDiceSpeechlet();
return await speechlet.GetResponseAsync(req);
}
}
RollTheDiceSpeechlet.cs
public class RollTheDiceSpeechlet : SpeechletBase, ISpeechletWithContext
{
public SpeechletResponse OnIntent(IntentRequest intentRequest, Session session, Context context)
{
try
{
// Default to 6 sides if not specified
if (!int.TryParse(intentRequest.Intent.Slots["DiceType"].Value, out int numSides))
numSides = 6;
var rollResults = new Random().Next(Math.Max(1, numSides - 1)) + 1; // Account for random returning '0'
return new SpeechletResponse
{
ShouldEndSession = false,
OutputSpeech = new PlainTextOutputSpeech { Text = $"I rolled a {numSides} sided die and got a {rollResults}." }
};
}
catch (Exception ex)
{
return new SpeechletResponse
{
ShouldEndSession = false,
OutputSpeech = new PlainTextOutputSpeech { Text = ex.Message }
};
}
}
public SpeechletResponse OnLaunch(LaunchRequest launchRequest, Session session, Context context)
{
return new SpeechletResponse
{
ShouldEndSession = false,
OutputSpeech = new PlainTextOutputSpeech { Text = "Welcome to the Roll the Dice. Ask me to roll the dice." }
};
}
public void OnSessionEnded(SessionEndedRequest sessionEndedRequest, Session session, Context context)
{
return;
}
public void OnSessionStarted(SessionStartedRequest sessionStartedRequest, Session session, Context context)
{
return;
}
}
JSON Input
Again, everything works fine but when I test it with Postman I get a 404 error.
The endpoint is C# serverless function that I developed in Visual Studio 201.
When I run it locally, I copy/paste the URL in the Postman app and send a post. See attached screenshots.
As the error suggest you are missing Signature and SignatureCertChainUrl headers. These helps to protect your endpoint and verify that incoming requests were sent by Alexa. Any requests coming from other sources should be rejected. When you test it via Test Console these headers are included and you get successful response.
Headers:
Signature
SignatureCertChainUrl
There are two parts to validating incoming requests:
Check the request signature to verify the authenticity of the request.
Check the request timestamp to ensure that the request is not an old request.
More information on verifying that the request was sent by Alexa here
I am getting 400 bad request when I am trying to pass a json array to spring controller on azure app service. However I am not getting any error when I try to run the service from my local environment. My request is as follows,
$http.post(appPath + '/app/temp/saveTempData?tempData=' + JSON.stringify(row.data)).success(function(result) {
if (result.result) {
toaster.pop("successful", "Updated successfully");
} else {
toaster.pop("warning", "Something went wrong please try again later.");
}
})
Where row.data is an json array.On the spring controller I have the following,
#RequestMapping(value = "/saveTempData", method = RequestMethod.POST)
#ResponseBody
public String saveTempData(#RequestParam JSONArray tempData) {
}
This code is working in my local machine, but on the azure app service it gives me 400 bad request. Thank you.
We have to encode the request parameter when sending json array to the app service controller using encodeURIComponent like follows,
$http.post(appPath + '/app/temp/saveTempData?tempData=' + encodeURIComponent(JSON.stringify(row.data))).success(function(result) {
if (result.result) {
toaster.pop("successful", "Updated successfully");
} else {
toaster.pop("warning", "Something went wrong please try again later.");
}
})
I'm struggling trying to find a working example of writing data to the Nest Thermostat API using plain rest. Attempting to write a C# app and cannot use Firebase. The multiple Curl examples posted so far do not work. I have a valid auth_token and can read data without issues. Finding the correct post url is elusive. Can anyone assist?
Examples like
curl -v -X PUT "https://developer-api.nest.com/structures/g-9y-2xkHpBh1MGkVaqXOGJiKOB9MkoW1hhYyQk2vAunCK8a731jbg?auth=<AUTH_TOKEN>" -H "Content-Type: application/json" -d '{"away":"away"}'
don't change any data.
Two things. First, follow redirects with -L. Second, put directly to the away data location, like
curl -v -L -X PUT "https://developer-api.nest.com/structures/g-9y-2xkHpBh1MGkVaqXOGJiKOB9MkoW1hhYyQk2vAunCK8a731jbg/away?auth=<AUTH_TOKEN>" -H "Content-Type: application/json" -d '"away"'
The PUT overwrites all data at a location. The previous command would logically be setting the structure's data to just {"away":"away"}.
user3791884,
Any luck with your C# PUT? Here is C# code that works:
using System.Net.Http;
private async void changeAway()
{
using (HttpClient http = new HttpClient())
{
string url = "https://developer-api.nest.com/structures/" + structure.structure_id + "/?auth=" + AccessToken;
StringContent content = new StringContent("{\"away\":\"home\"}"); // derived from HttpContent
HttpResponseMessage rep = await http.PutAsync(new Uri(url), content);
if (null != rep)
{
Debug.WriteLine("http.PutAsync2=" + rep.ToString());
}
}
}
Debug.WriteLine writes this to the Output window:
"http.PutAsync2=StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Access-Control-Allow-Origin: *
Cache-Control: no-cache, max-age=0, private
Content-Length: 15
Content-Type: application/json; charset=UTF-8
}"
These two methods return a valid structure of my data.
1/ command line
curl -v -k -L -X GET "https://developer-api.nest.com/structures/Za6hCZpmt4g6mBTaaA96yuY87lzLtsucYjbxW_b_thAuJJ7oUOelKA/?auth=c.om2...AeiE"
2/ C#
private bool getStructureInfo()
{
bool success = false;
try
{
// Create a new HttpWebRequest Object to the devices URL.
HttpWebRequest myHttpWebRequest=(HttpWebRequest)WebRequest.Create("https://developer-api.nest.com/structures/?auth=" + AccessToken);
// Define the request access method.
myHttpWebRequest.Method = "GET";
myHttpWebRequest.MaximumAutomaticRedirections=3;
myHttpWebRequest.AllowAutoRedirect=true;
myHttpWebRequest.Credentials = CredentialCache.DefaultCredentials;
using(HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse())
{
if (null != myHttpWebResponse)
{
// Store the response.
Stream sData = myHttpWebResponse.GetResponseStream();
// Pipes the stream to a higher level stream reader with the required encoding format.
StreamReader readStream = new StreamReader (sData, Encoding.UTF8);
Debug.WriteLine("Response Structure stream received.");
string data = readStream.ReadToEnd();
Debug.WriteLine(data);
readStream.Close();
success = deserializeStructure(data);
}
}
}
catch (Exception ex)
{
Debug.WriteLine("getStructure Exception=" + ex.ToString());
}
return success;
}