Draft 1
Inspiration gathered from Foursquare and Bit.ly APIs.
All requests are made against https://demokratiappen.se/api/v1
and all request bodies are expected to be json formatted. This applies even if the Content-Type: application/json
is not set.
Responses are wrapped in a json envelope:
{
"status_code": int,
"status_text": string,
"response": json
}
status_code
is the same HTTP status code that is returned in the header and the status_text
is a human readable description of the error. Where possible the error is more specific than what the HTTP code represents.
TODO
TBD
Demokratiappen supports a subset of the OAuth2 specification for authentication using username and password.
A POST
request is sent to /oauth/access_token
as follows:
POST /oauth/access_token HTTP/1.1
Host: https://demokratiappen.se/api/v1
Authorization: Basic czZCaGRSa3F0MzpnWDF
Content-Type: application/json
{
"grant_type": "password",
"username": string,
"password": string
}
Where Authorization
is mandatory and contains the value "Basic " + base64encode(client_id + ":" + client_secret)
. Client ID and client secret can be obtained here: .
The response, if authorization is successful, includes an access token.
{
"access_token": "e663e30818201d28dd07803e57333bed4f15803a"
}
Alternatively, a curl
request may be executed as this:
curl -u "CLIENT_ID:CLIENT_SECRET" -H "Content-Type: application/json" -d '{"grant_type=password", "username=USERNAME", "password=PASSWORD" }' https://demokratiappen.se/api/v1/oauth/access_token
Requires user authentication.
GET /users/me
returns 200 OK
and a user object.
{
"userid": string,
"username": string,
"email": string,
"created": datetime,
"updated": datetime,
"summary": {
"tags": int,
"articles": int
},
"tags": "https://demokratiappen.se/api/v1/users/me/tags",
"articles": "https://demokratiappen.se/api/v1/users/me/articles",
}
If not authenticated, return 401 Unauthorized
.
POST /users/me
where body includes a JSON object that specifies which fields to update.
{
"email": "new email"
}
Return 405 Method Not Allowed
if trying to modify a field which is not modifieable.
GET /users/me/tags
returns 200 OK
and a list of all tags made by user.
{
"userid": string,
"tags": [
{
"tagid": string,
"name": string,
"type": string,
"counts": {
"negative": int,
"positive": int
},
"ref": "https://demokratiappen.se/api/v1/tags/:tagid"
}
]
}
Possible optional parameters to request:
limit=int
offset=int
GET /users/me/tags/:tagid
to get a specific tag.
{
"userid": string,
"tag": {
"tagid": string,
"name": string,
"type": string,
"counts": {
"negative": int,
"positive": int
},
"ref": "https://demokratiappen.se/api/v1/tags/:tagid"
}
}
Returns 404 Not Found
if user hasn't tagged that particular tag.
GET /users/me/articles
returns 200 OK
and a list of articles by user.
{
"userid": string,
"articles": [
{
"articleid": string,
"title": string,
"url": string,
"ref": "https://demokratiappen.se/api/v1/articles/:articleid"
"tagsInArticle": [
{
"tagid": string,
"name": string,
"type": string,
"counts": {
"negative": int,
"positive": int
},
"ref": "https://demokratiappen.se/api/v1/tags/:tagid"
}
]
}
]
}
Possible optional parameters to request:
limit=int
offset=int
GET /users/me/articles/:articleid
to get a specific article, returns 200 OK
and
{
"userid": string,
"article": {
"articleid": string,
"title": string,
"url": string,
"ref": "https://demokratiappen.se/api/v1/articles/:articleid"
"tagsInArticle": [
{
"tagid": string,
"name": string,
"type": string,
"counts": {
"negative": int,
"positive": int
},
"ref": "https://demokratiappen.se/api/v1/tags/:tagid"
}
]
}
}
Returns 404 Not Found
if user hasn't saved that particular article.
Make a GET /tags
with the possible optional parameters
limit=int
offset=int
Returns 200 OK
and
{
"tags": [
{
"tagid": string,
"name": string,
"type": string,
"totalCounts": {
"negative": int,
"positive": int,
"seen": int
},
"ref": "https://demokratiappen.se/api/v1/tags/:tagid"
}
],
// if limit is used
"limit": int,
"offset": int,
"next": "https://demokratiappen.se/api/v1/tags?offset=(offset+limit)&limit=limit"
}
Make a GET /tags/:tagid
, returns 200 OK
and
{
"tagid": string,
"name": string,
"type": string,
"totalCounts": {
"negative": int,
"positive": int,
"seen": int
},
"ref": "https://demokratiappen.se/api/v1/tags/:tagid",
"inArticles": [
{
"articleid": string,
"ref": "https://demokratiappen.se/api/v1/articles/:articleid"
}
]
}
Make a GET /articles/
with possible optional parameters
limit=int
offset=int
query=tag1,tag2,tag2
- could possible be made more specific, e.g.,contains
and returns 200 OK
and the following body
{
"articles": [
{
"articleid": string,
"title": string,
"url": string,
"ref": "https://demokratiappen.se/api/v1/articles/:articleid",
"tagsInArticle": [
{
"tagid": string,
"name": string,
"type": string,
"ref": "https://demokratiappen.se/api/v1/tags/:tagid"
}
],
"extract": string, // ingress or similar from article
"matches": [
{
"tagid": string,
"ref": "https://demokratiappen.se/api/v1/tags/:tagid"
}
] // only if query param is provided
}
],
// only if limit is provided
"offset": int,
"limit": int,
"next": "https://demokratiappen.se/api/v1/articles?offset=(offset+limit)&limit=limit"
}
Make a GET /articles/:articleid
. There are no optional parameters.
{
"articleid": string,
"title": string,
"url": string,
"ref": "https://demokratiappen.se/api/v1/articles/:articleid",
"tagsInArticle": [
{
"tagid": string,
"name": string,
"type": string,
"ref": "https://demokratiappen.se/api/v1/tags/:tagid"
}
],
"fulltext": string
}
Requires user authentication.
POST /articles/add
returns 201 Created
and the new article object. (TBD: consider POST /users/me/articles
)
Request (all fields are optional unless otherwise stated)
{
"url": string, // required
"title": string,
"theme": string
}
Response
{
"article": {
"articleid": string,
"title": string,
"url": string,
"ref": "https://demokratiappen.se/api/v1/articles/:articleid"
"tagsInArticle": [
{
"tagid": string,
"name": string,
"type": string,
"ref": "https://demokratiappen.se/api/v1/tags/:tagid"
}
]
}
}
Once an article is created, a second request can be sent to rate the article. Only one rate request is allowed. All subsequent rate requests return 403 Forbidden
.
To rate an article, send a POST /articles/:articleid/rate
with the body:
{
"ratings": [
{
"tagid": string,
"rating": string // negative || positive
}
]
}
Correct requests return 200 OK
with an empty body.
If a tagid
is not included the tag is left unrated. If at least one tagid
is not correct or does not apply for the articleid
an error response 400 Bad Request
is returned. The body details which tagid
is failing. Either all is applied or an error is generated and rating can be redone.
{
"status_code": int,
"status_text": string, // message to user describing the error
"response": {
"failedTagids": [:tagid]
}
}