I am trying to call following API:
http -v -a qi.test.ac#gmail.com:pasword -f POST 'http://localhost:8080/api/v1/user/messages' from="qi.test.ac#gmail.com" to={"qi.test.ac#gmail.com","qi_test_ac#yahoo.com"} subject="test_sub" bodyText="testing hello"
I successfully called it from terminal using HTTPie using normally above command.
Now I want to call it from Alamofire. I have tried in following way:
parameters = [
"from" : fromMail,
"to" : ["qi.test.ac#gmail.com","qi_test_ac#yahoo.com"]
]
parameters["subject"] = message.getSubject()
parameters["bodyText"] = message.getBodyText()
Alamofire.request(.POST, urlString, parameters: parameters)//, encoding: .JSON)
.authenticate(user: userName, password: password)
.validate(statusCode: 200..<201)
.validate(contentType: ["application/json"])
.responseJSON {
(_, _, jsonData, error) in
if(error != nil) {
println("\n sendMessage attempt json response:")
println(error!)
delegate?.messageSent?(false)
return
}
println("Server response during message sending:\n")
let swiftyJSONData = JSON(jsonData!)
println(swiftyJSONData)
delegate?.messageSent?(true)
}
I have tried by url encoding which is by default and also in json encoding. But not succeeded yet. Any idea?
Thanks in advance.
Related
When my Telegram bot sends sendMessage to Telegram server it gets the error message:
{"ok":false,"error_code":400,"description":"Bad Request: message text is empty"}
The problem appeared this morning, before that my bot worked a whole year without errors. GetUpdates command works well as before. I use GET HTTP method to send commads:
https://api.telegram.org/bot<MyToken>/sendMessage
with UTF-8-encoded data attached:
{"chat_id":123456789,"text":"any text"}
Has anyone encountered this?
If the issue still persists, try to modify your curl request. For me adding header
'Content-Type: application/json' and -d '{"chat_id":12309832,"text":"any text"}' fixed issue
Another way to send a message by emulating a form :
curl -s -X POST https://api.telegram.org/bot{apitoken}/sendMessage \
-F chat_id='-1234567890' -F text='test message'
Well, i wrote wrapper on C language to communicate via SSL with telegram bot api. SO now I can clearly answer questions about telegram API spec.
Problem number one
First of all if we are talking about raw queries we need to remember about specifications.
By default HTTP/HTTPS post requests should consists of:
<METHOD>[space]<PATH with only valid chars> <\r\n>
<HOST valid regexed\r\n>
<Content-type valid regexed><\r\n>
<Content-Length with length of your POST body data><\r\n>
<\r\n before body>
<body>
So, i tried to send raw queries with out Content-Length and i had error same as yours. That's the first problem.
Problem number two
By default if you trying to send non valid request with sendMessage method - telegram bot api will response with error same as yours. So, yeah, that's pretty tricky error to debug...
If you trying to send raw query, be sure that your JSON data is serialized nicely and there is no errors like shielding.
Summarizing
Request:
POST /bot<token>/sendMessage HTTP/1.1
Host: api.telegram.org:443
Connection: close
Content-Type: application/json
Content-Length: 36
{"chat_id":<integer>, "text":"test \\lol"}
Second backslash if shielding.
Code on C
sprintf(reqeustCtx.request,
"POST /bot%s/%s HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s\r\n", bot_token, bot_method,
reqeustCtx.res_addr, strlen(body), body);
BIO_puts(bio, reqeustCtx.request);
BIO_flush(bio);
memset(reqeustCtx.response, '\0', BUFFSIZE);
read_bytes = BIO_read(bio, reqeustCtx.response, BUFFSIZE);
if (read_bytes <= 0) {
printf("No response");
exit(-1);
}
cert_free(cert_store, ssl_ctx, ca_cert_bio);
// free memory //
reqeustCtx.method(reqeustCtx.res_addr, reqeustCtx.request,
reqeustCtx.current_work_dir, reqeustCtx.current_cert);
/* json response, need to parse */
return reqeustCtx.response;
I got this error too.
I used sendMessage() method only with "low-level" Node https:
const https = require('https');
const data = JSON.stringify({
chat_id: config.telegram.chatId,
text: 'some ASCII text'),
});
const options = {
hostname: 'api.telegram.org',
port: 443,
path: `/bot${config.telegram.botToken}/sendMessage`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
const req = https.request(options, (res) => {
let chunks = [];
res.on('data', chunk => chunks.push(chunk));
res.on('end', () => {
const resBody = Buffer.concat(chunks).toString('utf8');
if (res.statusCode === 200) {
console.log(`Message sent`);
} else {
console.error(`${res.statusCode} ${res.statusMessage} ${res.headers['content-type']}
${resBody}`)
}
});
});
req.on('error', (error) => {
reject(error)
});
req.write(data);
req.end();
And for ASCII text it was ok, however for some non-ASCII text I got:
const data = JSON.stringify({
chat_id: config.telegram.chatId,
text: 'Привет Мир!'),
});
Error:
400 Bad Request application/json
{"ok":false,"error_code":400,"description":"Bad Request: message text is empty"}
In my case content length was calculated with invalid length 'Content-Length': data.length (invalid for Telegram?...), so I comment out this header and now it works for UTF-8!
headers: {
'Content-Type': 'application/json',
//'Content-Length': data.length
}
In my case, I was using curl_setopt($this->curl, CURLOPT_POSTFIELDS, json_encode($fields)); to post this json via sendMessage method:
{
"chat_id":000000000,
"text":"Choose one of the following options: ",
"reply_to_message_id":292,
"reply_markup":{
"keyboard":[
[
"Enable",
"Disable"
]
]
}
}
The problem was that when passing fields to the curl_setopt method, I was encoding the whole php array so I solved it by just encoding the reply_markup array which was a part of my json.
Try to put "Message" object with chat_id & text to HttpEntity in your restTemplate service, like below:
public MessageDto sendMessage(Message message) {
return restTemeplate.exchange(
"https://api.telegram.org/bot{token}/sendMessage",
HttpMethod.POST,
new HttpEntity<>(message, HttpHeaders.EMPTY),
MessageDto.class
).getBody();
}
After updating to xcode8 Alamofire4, my AlamofireRequest is not working, returning " status code: 401, headers" (unauthorised) on the request. The user authorisation is correct (I have checked the site). I do not have any compiler errors, but note that 'headers' is not highlighted in blue as usual, so am thinking that it is not recognising the headers properly. Am I doing something wrong with the 'headers' here?
let user = "sampleUser"
let password = "samplepass"
let credentialData = "\(user):\(password)".data(using: String.Encoding.utf8)!
let base64Credentials = credentialData.base64EncodedString(options: [])
let headers = ["Authorization": "Basic \(base64Credentials)"]
var checkUserEndpoint: String = "https://sample.com/ios1/user/\(uidEntered!).json"
print(checkUserEndpoint)
Alamofire.request(checkUserEndpoint, method: .get, parameters: nil, encoding: JSONEncoding.default, headers : headers)
.responseJSON { response in
print(response.request)
print(response.response)
print(response.data)
I have already tried using this instead for the headers, but it made no difference:
var headers: HTTPHeaders = [:]
if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {
headers[authorizationHeader.key] = authorizationHeader.value
}
also I tried this and it made no difference;
Alamofire.request(checkUserEndpoint,
method: .get,
parameters: nil,
encoding: JSONEncoding.default)
.authenticate(user: "sampleUser", password: "samplepass")
.validate()
.responseJSON { response in
print(response.request)
print(response.response)
print(response.data)
// print(response.error)
I've done similar migration twice, and my educated guess is that one of your strings you pass to generate headers value is Optional, ie. user, password or base64Credentials; though generating Optional("thestring") instead "thestring". You can try to wrap the request like this:
if let user = user, password = password, base64Credentials = base64Credentials {
let headers = ["Authorization": "Basic \(base64Credentials)"]
var checkUserEndpoint: String = "https://sample.com/ios1/user/\(uidEntered!).json"
print(checkUserEndpoint)
Alamofire.request(checkUserEndpoint, method: .get, parameters: nil, encoding: JSONEncoding.default, headers : headers)
.responseJSON { response in
print(response.request)
print(response.response)
print(response.data)
}
This can happen eg. in a situation, where those values coming from the Objective-C code, where the variables are not marked nonnull.
... base64Credentials should not be optional though, as stated in the documentation.
The code is correct in both variants (manual header creation and Alamofire request .authenticate usage). Looks like server side issue, use curl/postman or any other REST client to receive success response from your server before continuing your app development.
In Google documentation (https://developers.google.com/url-shortener/v1/getting_started), to use Google URL shortener, I should make a request as below:
POST https://www.googleapis.com/urlshortener/v1/url
Content-Type: application/json
{"longUrl": "http://www.google.com/"}
They also stated that I will have to authenticate:
"Every request your application sends to the Google URL Shortener API
needs to identify your application to Google. There are two ways to
identify your application: using an OAuth 2.0 token (which also
authorizes the request) and/or using the application's API key."
I chose public API key as a method to authenticate: I create a public key for my iOS app. Then I use the following code to POST (AFNetworking, using Swift):
func getShortURL(longURL: String){
let manager = AFHTTPRequestOperationManager()
let params = [
"longUrl": longURL
]
manager.POST("https://www.googleapis.com/urlshortener/v1/url?key={my_key_inserted}", parameters: params, success: {
(operation: AFHTTPRequestOperation!,responseObject: AnyObject!) in
println("JSON: " + responseObject.description)
},
failure: { (operation: AFHTTPRequestOperation!,error: NSError!) in
println("Error while requesting shortened: " + error.localizedDescription)
})
}
However, I got the log: Error while requesting shortened: Request failed: bad request (400).
Please tell me how to fix it.
What you are missing is setting the right AFNetworking serializer for this request.
Since the Google response is in JSON, you should use AFJSONRequestSerializer.
Add manager.requestSerializer = AFJSONRequestSerializer() like this:
let manager = AFHTTPRequestOperationManager()
manager.requestSerializer = AFJSONRequestSerializer()
let params = ["longUrl": "MYURL"]
manager.POST("https://www.googleapis.com/urlshortener/v1/url?key=MYKEY", parameters: params, success: {(operation: AFHTTPRequestOperation!,responseObject: AnyObject!) in
println("JSON: " + responseObject.description)
}, failure: { (operation: AFHTTPRequestOperation!,error: NSError!) in
println("Error while requesting shortened: " + error.localizedDescription)
})
I have an issue with AFNetworking and AFJSONRequestSerializer. I try to access an API, and the request contains a text/plain header. Here's my code :
class BaseService {
var manager: AFHTTPRequestOperationManager!
init() {
manager = AFHTTPRequestOperationManager()
manager.responseSerializer = AFJSONResponseSerializer()
manager.requestSerializer = AFJSONRequestSerializer(writingOptions: NSJSONWritingOptions.allZeros)
}
}
class UserService: BaseService {
func startNewEntry(name: String) {
let params = [
"time_entry": [
"description": name,
"created_with": "fooBar"
]
]
manager.POST(
"endpoint",
parameters: params,
success: { (operation, response) -> Void in
let json = JSON(response)
println("OK")
println(json)
Context.shared.entries.getFromJSON(json)
}) { (operation, error) -> Void in
println("-- ERROR --")
println(operation)
println(error)
}
}
Do you know this issue ?
No, this code will create a request with a content type of application/json. But I wonder if you perhaps mislead by an error message that said:
Request failed: unacceptable content-type: text/html
If you got that, that's not telling you that that the request had an unacceptable content type, but rather that the request failed because the response was text/html. And this is a very common issue: If server code that is attempting to create a JSON response fails for some reason, sometimes the error message isn't JSON, but rather it's HTML.
I would suggest adding the following inside the failure block of your POST method in order to see what this text/html response was:
if operation.responseData != nil {
println(NSString(data: operation.responseData, encoding: NSUTF8StringEncoding))
}
This way, if you get a text error message from the server (e.g. the request was malformed or what have you), you'll be able to read the HTML response you got back.
Trying to connect to this WebCEO API.
function getProjects() {
var payload = {
"key": "CUSTOMER_KEY",
"method": "get_projects"
};
payload = JSON.stringify(payload);
var url = "https://online.webceo.com/api/";
var options = {
"method": 'POST',
"contentType" : "application/json",
"payload": payload
};
var response = UrlFetchApp.fetch(url, options);
}
Receiving "Request failed for https://online.webceo.com/api/ returned code 404".
Any hint on what else I need to include / change?
Body must contain the following:
json={"key": "YOUR_API_KEY", "method": "get_projects"}
Well, https://online.webceo.com/api/ does return a 404 when you just try to access it. Did you manage to get that page to not return a 404 error from another client?
Doing so will probably tell you what you're missing here.
However, I'd suspect their API might be having issues.
That's true, you don't make a GET request. You have to send parameters in the body of a POST request. Below is an example in CURL for a situation when you need to get the list of projects:
curl -X POST -d 'json={"key": "YOUR_API_KEY", "method": "get_projects" }' https://online.webceo.com/api/