This is a collection of code snippets for various common tasks you might need to accomplish with the App.net API. Most of these are focused on creating or reading geo-tagged posts. They require a developer account on app.net and at least one of an App ID, App Code, App Access Token or User Access Token. The calls here are implemented using jQuery but that's just to make it easier to copy-paste into the console to test them out (so long as you fill in the blanks).

An important thing to bear in mind is the possibility for confusion between a 'stream' and 'streams'. By default, a 'stream' is a discrete chunk of the 20 latest posts served at a number of endpoints. This is the open, public, global stream:

https://alpha-api.app.net/stream/0/posts/stream/global

On the other hand, 'streams' are long-poll connections that serve up any matching posts as soon as they are created. The connection stays open while there is something there to receive the response. Streams are available under:

https://alpha-api.app.net/stream/0/streams

Totally not confusing. Not at all.


Creating a user access token

Required for any user-specific data retrieval. The only tricky thing you'll need to think about here is the scope you require.

scope=stream email write_post follow messages export

should cover most requirements.

Requires

  • client_id

Visit this URL:

https://alpha.app.net/oauth/authenticate
    ?client_id=[your client ID]
    &response_type=token
    &redirect_uri=http://localhost/
    &scope=stream email write_post follow messages export

Using a user access token to create a post (with annotations)

Requires

  • User Access Token
  • text to post

The text is essential if you don't mark a post as 'machine_only'. The annotations here are optional. Annotations don't appear in the global stream unless the requesting client asks for them.

$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({
    "annotations": [{
      "type": "net.app.core.geolocation",
      "value": {
        "latitude": 52.5,
        "longitude": 13.3,
        "altitude": 0,
        "horizontal_accuracy": 100,
        "vertical_accuracy": 100
      }
    }],
    "text": "Don't mind me, just checking something out."
  }),
  dataType: 'json',
  success: function(data) {
    console.log("Text+annotation message posted");
  },
  error: function() {
    console.log("Text+annotation message failed");
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/posts?access_token={USER_ACCESS_TOKEN}'
});

Using a user access token to post a machine_only post (with annotations)

Requires

  • User Access Token

In this example, we're creating a post that won't show up in user's timelines and adding the 'well-known annotation' for geolocation.

$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({
    "annotations": [{
      "type": "net.app.core.geolocation",
      "value": {
        "latitude": 52.5,
        "longitude": 13.3,
        "altitude": 0,
        "horizontal_accuracy": 100,
        "vertical_accuracy": 100
      }
    }],
    machine_only: true
  }),
  dataType: 'json',
  success: function(data) {
    console.log("Non-text message posted");
  },
  error: function() {
    console.log("Non-text message failed");
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/posts?access_token={USER_ACCESS_TOKEN}'
});

Retrieve the global stream, including geo-annotated posts if there are any

Requires

  • User Access Token

This is a very basic call to retrieve the global stream but it also instructs the endpoint to return us all annotations and include machine-only posts.

var data = {
  "include_machine": 1,
  "include_annotations": 1,
  "access_token": "{USER_ACCESS_TOKEN}"
};

$.ajax({
    contentType: 'application/json',
    dataType: 'json',
    success: function(data) {
      console.log(data);
    },
    error: function(error, data) {
      console.log(error, data);
    },
    type: 'GET',
    url: 'https://alpha-api.app.net/stream/0/posts/stream/global',
    data: data
});

Creating an App Access Token

This is necessary for many of the streams operations. It is not used for individual user actions, only for application-wide actions.

Requires

  • client_id
  • client_secret

client_credentials is one of the four types of grant_type specified in the OAuth 2.0 specification. I had difficulty getting this to work when using a data object:

var data = {
    "client_id": "{CLIENT_ID}",
    "client_secret":"{CLIENT_SECRET}",
    "grant_type": "client_credentials"
};

The client_credentials kept throwing an error. Instead, sending this as a string worked fine:

$.ajax({
  contentType: 'application/json',
  data: 'client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&grant_type=client_credentials',
  dataType: 'json',
  success: function(data) {
    console.log(data);
  },
  error: function(error, data) {
    console.log(error, data);
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha.app.net/oauth/access_token'
});

One other thing to note is that this bit should be done server-side. This will throw a bunch of "…not allowed by Access-Control-Allow-Origin…" errors if you do it via jQuery.

Returns

{
    "access_token": "{APP_ACCESS_TOKEN}"
    }

Creating a streams format

Now you have your app access token, you can use it to tell the service what kind of data you want back. The streams offered in the API have two quite powerful aspects. Firstly, filters allow you to run many kinds of queries on the data before it is streamed to you so you don't need to recieve and process it all. Secondly, the decoupling of filters from streams means you can specify the data structure and requirements you want once then just access that custom endpoint to get the data you want back any time.

Requires

  • App access token

This first example just creates an unfiltered stream endpoint

$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({"object_types": ["post"], "type": "long_poll", "id": "1"}),
  dataType: 'json',
  success: function(data) {
    console.log(data);
  },
  error: function(error, responseText, response) {
    console.log(error, responseText, response);
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/streams?access_token={APP_ACCESS_TOKEN}'
});

Returns

{
    "data": {
        "endpoint": "https://stream-channel.app.net/channel/1/{LONG_RANDOM_ENDPOINT_URL}",
        "id": "77",
        "object_types": [
            "post"
        ],
        "type": "long_poll"
    },
    "meta": {
        "code": 200
    }
}

Using Filters to create a stream of geotagged posts

We'll specify some requirements for our filter now so that it only returns back a subset of posts. The rules we're specfying here are:

At least one item in the "/data/annotations/*/type" field
must "match"
the value "net.app.core.geolocation"

Requires

  • User access token

The field is specified in 'JSON Pointer' format. Within the response, there is a 'data' object and a 'meta' object. The data contains an 'annotations' object which contains an array of annotations, each of which has a type. This is represented as /data/annotations/*/type.

$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({"match_policy": "include_any", "clauses": [{"object_type": "post", "operator": "matches", "value": "net.app.core.geolocation", "field": "/data/annotations/*/type"}], "name": "Geotagged posts"}),
  dataType: 'json',
  success: function(data) {
    console.log(data);
  },
  error: function(error, responseText, response) {
    console.log(error, responseText, response);
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/filters?access_token={USER_ACCESS_TOKEN}'
});

Returns

The filter rules you just specified, the id of the filter (remember that for later) and the details of the application used to make the request.

{
"clauses": [
    {
        "field": "/data/annotations/*/type",
        "object_type": "post",
        "operator": "matches",
        "value": "net.app.core.geolocation"
    }
],
"id": "527",
"match_policy": "include_any",
"name": "Geotagged posts",
"owner": {
    "avatar_image": {
        "height": 200,
        "url": "https://d2rfichhc2fb9n.cloudfront.net/image/4/Pr63PjEwJ1fr5Q4KeL3392BMgSnIAYlHxv8OkWwzx75V8quNfpaFp4VPpKnDRxdXtYYPtIutrDVdU9NbJn7hKApQL84T5sfB1D9bWTgtizMWInignv0WyPPfM2DpqSThQgvkB68vbPzjZ8VeKM02M2GySZ4",
        "width": 200
    },
    "canonical_url": "https://alpha.app.net/thingsinjars",
    "counts": {
        "followers": 30,
        "following": 65,
        "posts": 96,
        "stars": 0
    },
    "cover_image": {
        "height": 230,
        "url": "https://d2rfichhc2fb9n.cloudfront.net/image/4/UWZ6k9xD8_8LzEVUi_Uz6C-Vn-I8uPGEBtKb9jSVoFNijTwyEm1mJYpWq6JvnA6Jd4gzW76vFnbSWvM3jadhc1QxUl9qS4NTKiv3gJmr1zY_UpFWvX3qhOIyKrBPZckf2MrinqWay3H0h9rfqY0Gp9-liEg",
        "width": 960
    },
    "created_at": "2012-08-12T17:23:44Z",
    "description": {
        "entities": {
            "hashtags": [],
            "links": [],
            "mentions": []
        },
        "html": "<span itemscope="https://app.net/schemas/Post">Nokia Maps Technologies Evangelist; CreativeJS team member; the tech side of museum140; builder of The Elementals; misuser of semi-colons;rn</span>",
        "text": "Nokia Maps Technologies Evangelist; CreativeJS team member; the tech side of museum140; builder of The Elementals; misuser of semi-colons;rn"
    },
    "id": "3191",
    "locale": "en_GB",
    "name": "Simon Madine",
    "timezone": "Europe/Berlin",
    "type": "human",
    "username": "thingsinjars"
}
}

Listening to the geotagged post stream

This wil return a link to a long-lasting connection to the app.net stream that will only return posts with the geolocation annotation.

Requires

  • filter_id from the previous call

Note: the filter_id was returned as id in the previous response.

$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({"object_types": ["post"], "type": "long_poll", "filter_id": "527"}),
  dataType: 'json',
  success: function(data) {
    console.log(data);
  },
  error: function(error, responseText, response) {
    console.log(error, responseText, response);
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/streams?access_token={APP_ACCESS_TOKEN}'
});

Returns

The same kind of response as the 'Creating a streams format' example except the data coming down on the stream is filtered.

https://stream-channel.app.net/channel/1/{LONG_RANDOM_ENDPOINT_URL}

Open that URL up in your browser (seeing as we're testing) and, in a different tab, create a geo-tagged machine-only post (see above). Your post will appear almost instantly after you've submitted it.