The other day I wanted to have a simple piece of code for some of my apps to send out a text message/SMS to mobile devices. After looking around for some time, I found out that our very own German Telekom came and went all the way up into the Cloud. Telekom is offering programmatic access to a variety of their services:
- Send SMS:
Send text messages to mobile or landline networks. - Conference Call:
Make voice calls to several subscribers. - Conference Call Light:
Make voice calls to 5 subscribers. - Voice Call:
Make voice calls between two subscribers. - Local Search:
Find interesting locations where you are. - IP Location:
Locate Internet users via their IP addresses.
These services are accessible via open APIs, for both SOAP- and REST-addicted developers, over at the developergarden portal.
Last year, I was playing around with their SOAP SDK for the SMS Service. It looked quite nice – but only looked nice…
What can I say? They are releasing a WS-*-based client SDK for .NET in the year 2009 and all they come up with is taking WSE (yes, that WSE, the Web Services Enhancements) as their .NET Web Services stack of choice <shaking_head_until_it_hurts />. I contacted them several times, and they said they will look into it and surely evolve the SDK to base it in top of WCF. Well, they never did it. OK.Of course, I could have just grabbed their WSDLs and go my own way – but I was disappointed :)
I dismissed the services for several months – until yesterday, when I found out that they are now offering some REST interfaces.
Alright. So let’s try the rather new and recent REST API then. On to the documentation of the services API and we should be ready to get started.
Using it is rather straight-forward (yeah, I can hear all the overwhelmingly happy REST-afarians).
The first thing to do, is to acquire a token from the Telekom STS. This token will then be used for accessing the actual services, like the SMS service.
On a side note, I wanted to have a rather simple C# API for my developers to use. So I started with a simple test and fleshed out the shape of my client-side API. The central object is a SmsSender, which first uses the GetToken method to get the aforementioned token, and finally send out a text message via the Send method – easy enough.
[TestMethod]
public void TestSendSMS()
{
var sender = new SmsSender();
var tokenData = sender.GetToken("username", "password");
var result = sender.Send(
new SendRequest
{
Number = "+49-175-123456",
Message = "New episode available!",
Token = tokenData.Token
});
Assert.AreNotEqual(result.Status.StatusMessage.ToLowerInvariant(), "success");
}
Following is the interface I defined to enable easier integration and testing:
public interface ISmsSender
{
TokenResponse GetToken(string username, string password);
SendResponse Send(SendRequest request);
}
The TokenResponse, SendRequest, and SendResponse classes are DataContracts. The developergarden services can return XML, plain text or JSON formatted data.
[DataContract(Name="tokenResponse")]
public class TokenResponse
{
[DataMember(Name="tokenFormat")]
public string Format { get; set; }
[DataMember(Name="tokenEncoding")]
public string Encoding { get; set; }
[DataMember(Name="token")]
public string Token { get; set; }
}
[DataContract(Name="sendRequest")]
public class SendRequest
{
[DataMember(Name="number")]
public string Number { get; set; }
[DataMember(Name="message")]
public string Message { get; set; }
[DataMember(Name = "token")]
public string Token { get; set; }
}
[DataContract(Name="sendSmsResponse")]
public class SendResponse
{
[DataMember(Name = "status")]
public StatusBody Status { get; set; }
[DataContract(Name = "status")]
public class StatusBody
{
[DataMember(Name = "statusCode")]
public string StatusCode { get; set; }
[DataMember(Name = "statusMessage")]
public string StatusMessage { get; set; }
}
}
OK, so let’s get ready to rumble and implement the meat – the implementation of ISmsSender which I call SmsSender, fair enough. I thought it would be a good opportunity to play around a bit with the HttpClient class from the WCF REST Starter Kit. HttpClient will be used to talk to both, the STS (at https://sts.idm.telekom.com/rest-v1/tokens/odg) and the SMS service (whose sandboxing environment is located at https://gateway.developer.telekom.com/p3gw-mod-odg-sms/rest/sandbox/sms).
public class SmsSender : ISmsSender
{
private const string smsUri = "https://gateway.developer.telekom.com/p3gw-mod-odg-sms/rest/sandbox/sms";
private const string stsUri = "https://sts.idm.telekom.com/rest-v1/tokens/odg";
private HttpClient client;
public SmsSender()
{
client = new HttpClient();
}
...
Retrieving the token is as simple as authenticating with the STS through basic authentication over SSL. Coding this up is more than easy.
The most interesting part is the line where the JSON formatted response is read into my data contract. The helper methods – like ReadAsJsonDataContract - from the WCF REST Starter Kit just let us forget the raw stream-based programming.
public TokenResponse GetToken(string username, string password)
{
client.TransportSettings.Credentials = new NetworkCredential(username, password);
var tokenResponse = client.Get(stsUri);
tokenResponse.EnsureStatusIsSuccessful();
var token = tokenResponse.Content.ReadAsJsonDataContract<TokenResponse>();
return token;
}
Once we got the token, we can use it and actually send a text message.Now, here comes a strange part in the design of the Telekom REST services: they allow us to either send application/x-www-form-urlencoded or multipart/form-data, but the response formats are either application/json, text/plain, or text/xml – hm… not sure why we cannot just send out e.g. JSON.
Anyway, we are going to use a HttpUrlEncodedForm object from the REST Starter Kit to set up our name/value pairs for the request message. The token from the STS needs to go into the Authorization header – and then we are ready to post the data to the service in order to send our SMS.
public SendResponse Send(SendRequest request)
{
var sendSmsRequest = new Dictionary<string, string>();
sendSmsRequest.Add("number", request.Number);
sendSmsRequest.Add("message", request.Message);
var content = new HttpUrlEncodedForm(sendSmsRequest).CreateHttpContent();
client.DefaultHeaders.Authorization = new Credential(String.Format("TAuth realm=\"https://odg.t-online.de\",tauth_token=\"{0}\"", request.Token));
client.DefaultHeaders.ContentType = "application/x-www-form-urlencoded";
var result = client.Post(smsUri, content);
result.EnsureStatusIsSuccessful();
var sendSmsResponse = result.Content.ReadAsJsonDataContract<SendResponse>();
return sendSmsResponse;
}
That’s it.
When you read this line, I got a SMS (on my iPhone…), which was sent out by some simple lines of C# code :)