Skip to content
programmingthomas edited this page Oct 22, 2012 · 6 revisions

API

One of the key aspects on Neon is that it should be open and extensible so we therefore wrote an API that gets used by both the JavaScript client side and is accessible to anyone else so that you can write apps that work on top of someone's Neon account. This documentation is preliminary and subject to change however contains basic detail on how you can use the API.

Background to the API

The API uses GET and POST requests and returns JSON. We use JSON purely over XML because all our server and client side code is written in JavaScript so it makes sense to use a technology that will work out the box with as little extra code as possible. Because posts are not publicly accessible we haven't implemented RSS/XML either.

General requests

All requests will go through http://server-route:port/api/ and will return JSON regardless of what happens (unless the server crashes). All responses will contain a JSON object in this style:

{
	"request": {
		"requestType": "requestType",
		"requestDetail": "requestDetail",
		"successCode": 200
	}
}

The requestType indicates what was requested, such as dashboard, user or inbox. Request detail will give the extra, optional part of the request, such as 20 for the request api/user/20. The success code is a standard HTTP request. Currently it will return things such as the following:

  • 200: Success
  • 400: More information required
  • 401: Unauthorized
  • 404: Not found

The HTTP status code returned in the header will always match the success code in case your application checks that. Please note that response section is not included in any other response examples in this documentation however will always be returned.

Authenticating

We wanted to be lazy when we wrote Neon so therefore there are only two methods of authentication. The first, which we use in the JavaScript client side code, is to send the username and password via a POST request to /api/login/. Here is an example:

Request:

POST: /api/login?username=exampleUsername&password=examplePassword

Response:

{
        "login": {
        	"username":"exampleUsername",
                "key":"abcdefghijklmnopqrstuvwxyz012345abcdefghijklmnopqrstuvwxyz012345",
                "userId":id,
                "name":"Example name",
                "userImage":"/images/id.png",
                "groupIds":[12, 13, 14, 18],
                "groupNames":["Socials", "Phsyics 11A", "Maths 11.1", "English 11M1"]
        }
}

The key is randomly generated on the server and will work for up to a month, at which point the key will expire and you will receive a 401 response, requiring you to login again. Each time you make a request you should also send the username and key. This is beneficial for GET requests as it doesn't contain the password and is therefore less easy to watch, and it also means that you never have to store the password client side.

Alternatively you can authenticate requests by sending username and password for each request however we don't believe that this is as secure.

API options

The following is an incomplete list of all of the API options. We intend to keep this documentation up to date. Please note that all requests require the username and key or password property. If you are learning the API you may wish to add the optional whitespace parameter to get easier to read JSON.

Full list of documented API functions:

  • /api/login/ - login to service
  • /api/user/ - get user detail
  • /api/group/ - get group detail
  • /api/dashboard/ - get dashboard
  • /api/dashboard/search/ - get search results for posts
  • /api/post/ - post a message
  • /api/addNoteToPost/ - like, dislike or repost a post
  • /api/searchusers/ - search users
  • /api/inbox/ - get inbox notifications
  • /api/inbox/compose/ - send a direct message to another user
  • /api/outbox/ - read sent messages
  • /api/inbox/read/ - mark a message as read
  • /api/inbox/delete - delete a message

Full list of undocumented API functions:

  • /api/post/delete - delete a post
  • /api/register - register a new user
  • /api/group/join/ - opt to join a group
  • /api/group/approve - approve a user to a group
  • /api/group/unjoin/ - opt out of a group

Full list of undocumented, nonexistent functions I would like to see:

  • /api/stats/ - get stats on the site such as total posts/groups

/api/user/

This request allows you to fetch user information and the most recent posts that are visible to the logged in user. This means that the user information is public, however only posts that were submitted to groups that you and the user are members of will be visible. You can use either a GET or POST request to access this.

By default, the fifty most recent posts are returned however if you want to request earlier posts please use offset=integer where integer begins at 0 for the most recent post.

Example requests:

GET /api/user/20
GET /api/user/thomas
GET /api/user/20?offset=20
POST /api/user/20?offset=50

Example response:

{
    "user":{
        "userId":20,
        "username":"thomas",
        "name":"Thomas :)",
        "groupIds":[12, 13, 14, 18],
        "groupNames":["Socials", "Phsyics 11A", "Maths 11.1", "English 11M1"],
        "userImage":"/images/20.png",
        "posts":[
            {
                "postId":1,
                "plainText":"Hello, world!",
                "html":"<p>Hello, <em>world</em>!",
                "groupId":12,
                "groupName":"Socials",
                "groupColor":"#123456",
                "likes":10,
                "dislikes":1,
                "reposts":[7,8,10,24],
                "jsonTime":"Sat Oct 20 2012 16:33:08 GMT+0100 (GMT Daylight Time)",
                "time":1234567890,
            },...
        ]
    }
}

The group IDs and Names are all the groups that a user is a member of. Each post is a simplified version of a standard post response and contains the key information. For information, scroll to the Dashboard section.

###/api/group/ This request allows you to get information about a specific group either through a GET or POST request. You will only get post data from the group if the user whose details you are using is a member of that group. Like /api/user/ and /api/dashboard/ requests this will quite happily accept an offset parameter.

Example requests:

GET /api/group/1
GET /api/group/1?offset=10
POST /api/group/1?offset=50

Example response if the user is not able to see posts:

{
    "group":{
        "groupId":1,
        "groupName":"Staff",
        "groupCreator":{
            "userId":20,
            "username":"thomas",
            "name":"Thomas :)",
            "groupIds":[1, 12, 13, 14, 18],
            "groupNames":["Socials", "Phsyics 11A", "Maths 11.1", "English 11M1"],
            "userImage":"/images/20.png"
        },
        "groupColor":"#123456"
    }
}

Example response if is able to read posts:

{
    "group":{
        "groupId":1,
        "groupName":"Staff",
        "groupCreator":{
            "userId":20,
            "username":"thomas",
            "name":"Thomas :)",
            "groupIds":[1, 12, 13, 14, 18],
            "groupNames":["Socials", "Phsyics 11A", "Maths 11.1", "English 11M1"],
            "userImage":"/images/20.png"
        },
        "groupColor":"#123456",
        "posts":[
                {
                    "postId":1,
                    "plainText":"Hello, world!",
                    "html":"<p>Hello, <em>world</em>!",
                    "userId":20,
                    "username":"thomas",
                    "name":"Thomas :)",
                    "userImage":"/images/20.png",
                    "likes":10,
                    "dislikes":1,
                    "reposts":[7,8,10,24],
                    "jsonTime":"Sat Oct 20 2012 16:33:08 GMT+0100 (GMT Daylight Time)",
                    "time":1234567890
                },...
        ]
    }
}

The group ID is the database ID required for the request. The groupColor property isn't really needed by many applications but you may wish to show it when presenting which group a user posted a post in. We allow the group creator to change the group color however we may only get the Hue value from the hex code and set our own brightness and saturation levels. It is worth noting that members of a group are not returned because this will usually produce a very large array and it isn't needed by our client.

###/api/dashboard/ This can be used as a GET or POST request to get the posts for the current users' dashboard. This will include all posts from all groups that they are a member of. Again, this allows for an offset property to fetch older posts.

Example requests:

GET /api/dashboard
POST /api/dashboard
GET /api/dashboard?offset=50

Example response:

{
    "posts":[
        {
            "postId":1,
            "plainText":"Hello, world!",
            "html":"<p>Hello, <em>world</em>!",
            "userId":20,
            "username":"thomas",
            "name":"Thomas :)",
            "userImage":"/images/20.png",
            "likes":10,
            "dislikes":1,
            "reposts":[7,8,10,24],
            "jsonTime":"Sat Oct 20 2012 16:33:08 GMT+0100 (GMT Daylight Time)",
            "time":1234567890,
            "groupId":12,
            "groupName":"Socials",
            "groupColor":"#123456"
        },...
    ]
}

Again, if the user is not authenticated no posts will be returned. We also recommend that there is a general group for all users so that therefore some posts will be returned. This is an example of the only time that all post data (user and group) will actually get returned.

###/api/dashboard/search/ This is an example of using the [option] on an API request. Using this you can search the posts on the user's dashboard.

Example requests:

GET /api/dashboard/search/?q=Hello+world
POST /api/dashboard/search?q=Hello+world&offset=50

The response will be exactly the same as a standard dashboard request. If you are caching dashboard posts in some sort of local storage/database you may wish to search locally instead.

/api/post/

This is a fun method. It is a POST request that lets the user interact with the service which is kinda important.

Example request:

POST /api/post/?groupId=12&content=URL%20escaped%20plain%20text&responding=idOfRespondingPost

If a user is responding to a post the groupId parameter then becomes optional however if they are both included then the postId should be for a post that is the group for groupId otherwise the request will fail. Please note that we don't actually store the responding post however it makes it easier for us to notify a user they have had a response.

Example response:

{
    "id":123456
}

The example response will only return an id if the post was successful and HTTP Status Code = 200. The id is the ID of the new post.

/api/addNoteToPost/

This method allows you to like, dislike or repost a post. The only required parameters are the id of the post and the action. If a user has already reposted a post it will fail. If they have already liked it it will be unliked and the same for the dislike operation.

Example requests:

POST /api/addNoteToPost/?operation=repost&id=10
POST /api/addNoteToPost/?operation=like&id=10
POST /api/addNoteToPost/?operation=dislike&id=10

The response will then include the new total number of likes and dislikes and if the user has reposted the post it will include the new repostId. Again, the HTTP error code will reflect success.

Example response:

{
    "likes":10,
    "dislikes":10,
    "repostId":120
}

/api/searchusers/

This GET or POST method will return a list of user objects whose name or username match the q parameter. You can optionally add an offset parameter.

Example request:

GET /api/searchusers/?q=thomas
POST /api/searchusers?q=thomas&offset=50

Example response:

{
    "users": [
        {
            "userId":20,
            "username":"thomas",
            "name":"Thomas :)",
            "groupIds":[12, 13, 14, 18],
            "groupNames":["Socials", "Phsyics 11A", "Maths 11.1", "English 11M1"],
            "userImage":"/images/20.png",
        ]
    }
}

The search results will return up to 50 matching users at a time. You should store which groups your user is in (which are provided when /api/login/ is called so that you can present whether or not the current user can access any posts from each user.

/api/inbox/

This method allows you to fetch all of the current Inbox posts. Messages are automatically sent from one user to another when an @response is used in a message text. The message content will be set to the content of the response, however the optional value directTo will indicate the postId. Obviously this is something that you should be checking reasonably often and we recommend that you don't check a server more often than about once every couple of minutes depending on the usage of that server and abilities of the client. If you can, cache inbox messages client side.

Example request:

GET /api/inbox/
POST /api/inbox/?offset=10&limit=10

As with dashboard requests there is an optional offset parameter however there is also a limit parameter as read messages are not returned by default. You can chose to add the parameter readmessages if you wish to receive these as well however you will not be able to set a limit and it will default to 25. The reason we do this is because read messages are irrelevant if displaying notifications and therefore they should only be displayed in a full inbox view.

Example response:

{
    "messages":[
        {
            "id":123456,
            "sender":{
                "id":20,
                "name":"Thomas :)",
                "username":"thomas",
                "userImage":"/images/20.png"
            },
            "plainText":"Hello, Thomas!",
            "html":"<p>Hello, Thomas!</p>",
            "timestamp":1234567890,
            "jsonTime":"Sat Oct 20 2012 16:33:08 GMT+0100 (GMT Daylight Time)",
            "directTo":12345,
            "read":false
        },...
    ]
}

Note that the read value will only be added if you have requested that read and unread messages should be fetched.

/api/inbox/compose

This POST request allows you to send a message to another user. It is pretty easy to send a message. Aside from the standard authentication all you have to is add a receiver and content parameter to the URL where the receiver is either the username of userId of the user you want to send a message to and content is the plain text content of the message. We'll strip HTML anyway or add in appropriate tags when serving up the message anyway.

Example request:

POST /api/inbox/compose/?receiver=20&content=Hello%20World!
POST /api/inbox/compose/?receiver=thomas&content=Hello%2C%20World!

Obviously your requests should be properly escaped. Currently the server will support sending messages to yourself but if this is abused we'll probably take that ability out especially given that it is almost completely pointless.

The response will just provide the ID of the sent message. The standard HTTP response codes detailed above will also reflect the status, so therefore anything but 200 would indicate a failure. Failures will not include a messageId:

{
    "messageId":123456
}

/api/outbox/

This method is exactly the same as Inbox although instead of a sender property it will include receiver information. A read property will not be returned unless we decide to implement read receipts in the future. But this seems unlikely. We like uncertainty :P.

/api/inbox/read/

This request allows you to mark a specific message as read.

Example request:

GET /api/inbox/read/?message=12
POST /api/inbox/read/?message=12

This will only succeed if the authenticated user is a receiver of that message. Nothing is returned other than the HTTP request content and a statusCode of 200 will indicate that the message was marked as read. Calling /api/inbox/read on a message that has already been marked as read will mark it is unread. Please note that you should not then request /api/inbox/ on each read update but should instead just update your own cached records and UI. Don't waste requests.

/api/inbox/delete/

This method matches /api/inbox/read/ except that you cannot undelete messages so it is probably worth notifying the user what they are doing before they do something stupid.