Twitter's 1.1/statuses/update.json
URL expects data to be encoded in application/x-www-form-urlencoded
format, so you need to set the TRESTClient.ContentType
property to ctAPPLICATION_X_WWW_FORM_URLENCODED
(it is set to ctNone
by default).
As for UTF-8, TRESTClient
uses Indy internally, and Indy supports encoding outbound data using user-specified charsets, but it does not appear that Embarcadero added that feature to its TRESTClient
interface (it does handle charsets in responses, though). I do not know why Embarcadero would omit such an important feature. It is not enough to just encode the string data as UTF-8 (which you are not doing correctly, BTW), but you also have to tell Twitter that the data has been UTF-8 encoded (via the charset
attribute of the Content-Type
REST header), and TRESTClient
does not allow you to do that, as far as I can see. I don't know if TRESTClient
sends REST requests with a default charset specified, but looking at its source, I don't think it does, but I have not tried it.
At the very least, you need to fix your EncodeAsUTF8()
function. It does not produce a UnicodeString
that holds UTF-8 encoded octets, like you think it does. It produces a UTF-8 encoded AnsiString
and then converts that to a UTF-16 encoded UniodeString
using the RTL's default Ansi codepage, so you are invoking a data conversion that loses the UTF-8 data. Try this instead:
function TTwitterApi.EncodeAsUTF8(UnicodeStr: string): string;
var
UTF8Str: UTF8String;
I: Integer;
begin
UTF8Str := UTF8String(UnicodeStr);
SetLength(Result, Length(UTF8Str));
for I := 1 to Length(UTF8Str) do
Result[I] := Char(Ord(UTF8Str[I]));
end;
That should allow TRESTClient
to url-encode the correct UTF-8 data in its POST data, at least. But you still have to deal with the issue of the missing charset
attribute in the Content-Type
request header (unless Twitter defaults to UTF-8 when no charset
is specified).
Now, with all of that said, if you find that working around the TRESTClient
problems does not work out for you, then I would suggest switching to Indy's TIdHTTP
component instead (which has a more accurate application/x-www-form-urlencoded
implementation than TRESTClient
is using), eg:
procedure TTwitterApi.Send(Tweet: string);
var
Params: TStringList;
begin
Reset;
Params := TStringList.Create;
try
FParams.Add('status=' + Tweet);
FIdHTTP.Request.ContentType := 'application/x-www-form-urlencoded';
FIdHTTP.Request.Charset := 'utf-8';
FIdHTTP.Post('https://api.twitter.com/1.1/statuses/update.json', Params, IndyTextEncoding_UTF8);
finally
Params.Free;
end;
end;