0

I've set up a simple web site consisting of a button with a JavaScript onclick method from which I want to send a push notification to my phone using Urban Airship.

If I use quotes around the data property, I get a "500 (Internal Server Error)". If I don't use quotes around the data property, I get a popup authorization window from Urban Airship in which I write my app key and master secret. It seems to accept this, but afterwards I get a "405 (Method Not Allowed)".

According to the Chrome Dev Tools, both ways get handled as a GET, even though it's specified as a POST (which is required). What could be wrong?

function sendButtonClick(){
    jQuery.ajax({
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        username:'my app key',
        password:'my app secret',
        url: 'https://go.urbanairship.com/api/push/broadcast/',
        data: {"android": {"alert": "alerttest", "extra": {"extra test": "extra value test"}}},
        dataType: 'jsonp',
    });
};

Thanks in advance!

jomni
  • 759
  • 8
  • 21
  • You can't `POST` across domains. – ahren Apr 18 '13 at 14:23
  • In the bottom of the official documentation at https://docs.urbanairship.com/display/DOCS/Server%3A+Android+Push+API it says "POST to /api/push/broadcast/". Did I misunderstand the POST aspect then? I've seen other examples that use similar syntax. – jomni Apr 18 '13 at 14:29
  • on regular desktop browsers, you can't POST across domains. I believe mobile has an exception - so it begs the question, are you testing on your mobile or on your desktop? – ahren Apr 18 '13 at 14:31
  • I'm testing on my desktop. What other options would I have? Would I have to create a stand-alone application? I would like to be able to send push notifications via Urban Airship from my custom web interface. – jomni Apr 18 '13 at 14:42
  • There are some emulators that may work. Otherwise you could plug your phone into your computer and use some remote debugging tools. Not sure about the app vs web interface question. – ahren Apr 18 '13 at 14:43
  • It seems a stand-alone application would be the only way to go. I'll try to connect the web interface with a simple backend that in turn sends the push notifications to Urban Airship. Thanks for the insight about POST not being possible across domains, think it put me in the right direction :) – jomni Apr 18 '13 at 15:15

2 Answers2

1

What is the server side technology you are using? You have to do this from there. basically, you cannot do Cross domain calls via a desktop browser. The way you can do this is, call your server side method with the payload and then have the server side send out the notification. Here is a sample code from c# I wrote.

 public interface INotification
{
    void Set(string deviceId, string alert, int? badge, string sound);
}

public class BaseNotification
{

    public List<string> Aliases { get; set; }
    public List<string> Tags { get; set; }
}

 public class iOSNotification : BaseNotification, INotification
{
    public List<string> Device_Tokens { get; set; }
    public NotificationBody aps { get; set; }

    public iOSNotification()
    {
        Device_Tokens = new List<string>();
    }

    public void Set(string deviceId, string alert, int? badge, string sound)
    {
        Device_Tokens.Add(deviceId);
        aps = new NotificationBody
        {
            Alert = alert,
            Badge = badge.HasValue ? badge.Value : 0,
            Sound = sound
        };
    }
}

//in a static extensions
 public static string ToJSONString<T>(this IEnumerable<T> items)
   {
        var jsonString =  JsonConvert.SerializeObject(items, Formatting.Indented, new JsonSerializerSettings
            {
                ContractResolver = new LowerCaseContractResolver(),
                NullValueHandling = NullValueHandling.Ignore
            });

        jsonString = jsonString.Replace("\r\n", string.Empty);

        return jsonString;

    }



protected internal void SendPushNotification(List<INotification> payLoad, string uriKey) {

        var json = payLoad.ToJSONString();
        var Uri = GetAppSettings(uriKey);
        var encoding = new UTF8Encoding();

        var contentLength = encoding.GetByteCount(json);

        var request = (WebRequest)WebRequest.Create(Uri);

        request.Method = "POST";
        CredentialCache credentialCache = new CredentialCache();
        credentialCache.Add(new Uri(Uri), "Basic", GetCredentials());

        request.Credentials = credentialCache;

        request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(new ASCIIEncoding().GetBytes(_username + ":" + _password)));
        request.ContentType = "application/json";
        request.ContentLength = contentLength;


        using (var stream = request.GetRequestStream()) {

            stream.Write(encoding.GetBytes(json), 0, contentLength);
            stream.Close();

            var response = request.GetResponse();

            response.Close();
        }

    }
Sujesh Arukil
  • 2,469
  • 16
  • 37
  • Alright, so I guess that's why there is no JavaScript api in https://docs.urbanairship.com/display/DOCS/Server%3A+Libraries . Seems the only working way is to create a stand-alone application then. Thanks for the input! – jomni Apr 18 '13 at 15:11
  • Well that has always been the idea. You need to create a server application to do this to access the urban airship apis. In a way, it is more secure and you are not throwing in your keys and passwords in your main application js. Just curious, what server side technology are you using? – Sujesh Arukil Apr 18 '13 at 16:22
  • just to add, you can do cors calls from modern desktop browsers that support it, but the server receiving your request, also need to allow it. so although possible to do exactly what you are trying here, the Urbanairship APIs do not support it. – Sujesh Arukil Apr 18 '13 at 16:24
  • I see, thanks for the information. Finally I ended up creating a simple C# ASP.NET web page in which I could combine the web interface with the server-side push taking place in the code-behind file. It was based on this http://stackoverflow.com/questions/2393725/iphone-push-notification-urbanairship . Working like a charm! – jomni Apr 18 '13 at 21:59
0

You won't be able to POST cross-domain in any browser, mobile or desktop. Your best option is to set up an endpoint on your server which expects the POST request from jQuery (e.g. yoursite.com/message/broadcast). Then, on the server, do a POST to https://go.urbanairship.com/api/push/broadcast. when it responds, send the response back as the response on your end.

you're better off keeping your API master password to yourself on your server.

NOTE: You'll want to make sure you don't include the API password on your client. In fact, I suggest leaving the auth header out in the client, and then add it on your server before sending the request off to UrbanAirship. So even if you could POST cross-domain (aka you were building an iOS native Cocoa application), you're still better off keeping the secure credentials on your server instead of the device)

For example, using Sails (javascript / Node.js server):

// api/MessageController.js
module.exports = {
  broadcast: function (req,res) {

   // Your message for UrbanAirship should be sent as JSON in req.body
   // e.g. req.body === '{ "android": { "alert": "foo" } } '

    var httpRequest = require('request');
    httpRequest({
      url: 'https://go.urbanairship.com/api/push/broadcast/',
      json: 'true',
      auth: {
        'user': 'YOUR_API_KEY',
        'pass': 'YOUR_MASTER_SECRET',
        'sendImmediately': true
      },
      body: req.body
    }, function (err) {

      // Send confirmation back to jQuery of either success (200) or error (500)
      if (err) res.send(err, 500);
      else res.send(200);

    });
  }
};
mikermcneil
  • 11,141
  • 5
  • 43
  • 70