StoryAPI (@never-no/story-api)
- Abstraction of 2 Story APIs:
- the XML-RPC based ones that are used for submitting votes, and an older interface for submitting messages
- a REST based API, for various other low-level operations, but also which must be used for submitting generic/custom messages (i.e. not originating on Facebook, Twitter, Instagram or other common social networks)
Usage
var NeverNoStory = require('./lib/never-no-story');
var story = new Story('storyXYZ.never.no');
Submitting votes
Votes can either be incremental (relative) or preaggregated (absolute) - keep this in mind in regard to the "count" variables when submitting votes.
Currently the only way of submitting votes is using the XML-RPC interface.
Return channel listings (how to obtain parameter values)
Manifest
If a poll data source supports a return channel it will have a listing that describes the method and parameters to use in the XML/JSON manifest.
Old format
The XML manifest will have a listing like:
<datasource mtime_unix="1474887993" mtime="2016-09-26T11:06:33.0243960Z" ttl="60" serial="20160926130633024" id="poll" subtype="vote" type="complete" href="root_poll.xml">
<return_channel type="story-xmlrpc-poll.submit" vote_type="incremental" search_id="19" poll_id="19" xmlrpc_url="http://storyrunetest.never.no:9191"/>
</datasource>
The JSON manifest will have a listing like:
{
"poll": {
"href": "root_poll.json",
"type": "complete",
"subtype": "vote",
"id": "poll",
"mtime": "2016-09-26T11:06:33.0243960Z",
"mtime_unix": 1474887993,
"ttl": 60,
"serial": 20160926130633024,
"return_channels": [{
"xmlrpc_url": "http://storyrunetest.never.no:9191",
"poll_id": 19,
"search_id": 19,
"vote_type": "incremental",
"type": "story-xmlrpc-poll.submit"
}]
},
In both these cases:
-
type
is alwaysstory-xmlrpc-poll.submit
-
xmlrpc_url
is the URL to the XML-RPC interface -
poll_id
is the poll ID -
search_id
is the search/index ID associated with this poll -
vote_type
is eitherincremental
oraggregated
New format (Story 1.7+)
An XML manifest will have a listing like:
<export ttl="60" serial="20160926140951835" id="poll" type="poll" modifiedTimestamp="1474891791835" modifiedIso8601="2016-09-26T12:09:51.8352391Z">
<link type="export" rel="related">root_poll.xml</link>
<returnChannel type="story-xmlrpc-poll.submit" voteType="incremental" searchId="19" pollId="19" xmlrpcUrl="http://storyrunetest.never.no:9191"/>
</export>
A JSON manifest will have a listing like:
{
"ttl": 60,
"serial": 20160926140951835,
"id": "poll",
"type": "poll",
"modifiedIso8601": "2016-09-26T12:09:51.8352391Z",
"modifiedTimestamp": 1474891791835,
"link": {
"type": "export",
"rel": "related",
"url": "root_poll.json"
},
"returnChannels": [{
"xmlrpcUrl": "http://storyrunetest.never.no:9191",
"pollId": 19,
"searchId": 19,
"voteType": "incremental",
"type": "story-xmlrpc-poll.submit"
}
In both these cases:
Same as the old format, but camelCase
instead of snake_case
:
type
xmlrpcUrl
pollId
searchId
voteType
Main export
In main exports of "old" formats (e.g. root_poll.xml):
-
poll_id
: seestory_poll_id
in the main poll entry -
search_id
: seesearch_id
in the main poll entry - aggregation type: see
aggregation_method
. "pre_aggregated_data" means preaggregated (absolute), all others mean incremental (relative)
Function
story.submitVote(pollId, searchId, votes, [callback]) // -> Promise
pollId
and searchId
can be retrieved from the return channel listing in the JSON/XML manifest.
- for "old" formats and
- for "new" formats: see TODO
The votes
argument is an object with keys being the alternative uuids, and values being the number of votes for that alternative.
If the poll is preaggregated, the number of votes should be the absolute number of votes to set. If the poll is incremental, the number of votes should be the relative number of votes to add.
Callback is an optional function(err, res)
style callback.
Returns a Promise object.
Example
var NeverNoStory = require('../lib/never-no-story');
var story = new NeverNoStory("storyrunetest.never.no");
story.submitVote(
35, // poll id
38, // search id
{
'91881a9a-35e3-aec1-af27-1542c88287bf': 1, // uuid alt 1
'1f4f2577-ffa8-4314-87a6-4f8ad64d2068': 2, // uuid alt 2
'5fe66e16-9537-7358-f455-ed8f62b109d3': 3 // uuid alt 3
})
.then(function(res)
{
console.log("OK! " + JSON.stringify(res))
},
function(err)
{
console.error("ERROR! " + err.message + ", at " + err.stack);
})
Submitting messages
Messages can be delivered using both the XML-RPC interface and the REST interface, but the XML-RPC interface has certain limitations which means the REST interface is preferred.
Return channel listings (how to obtain parameter values)
Manifest
If a message data source supports a return channel it will have a listing that describes the method and parameters to use in the XML/JSON manifest.
See the examples for poll for a generic outline of these listings - only the parameters are listed here.
Old format
-
type
is alwaysstory-rest-messages
-
base_url
is the base URL to the REST interfaces, use/messages
relative to this for the messages REST API -
search_id
is the search/index ID to submit the message to -
source_type
should bedocumentbin
New format (Story 1.7+)
Same as the old format, but camelCase
instead of snake_case
:
type
baseUrl
searchId
sourceType
Function
There are multiple entry points here, but the one that should be used is the submitGenericMessage()
function:
story.submitGenericMessage(searchId, message, [callback]) // -> Promise
searchId
is the Story bucket id, either retrieved from a return channel configuration listing in a JSON/XML manifest, or manually retrieved somehow.
message
is an object with the following properties:
-
author
: object with -
username
: username/screen name/handle -
name
: full name -
picUrl
(optional) -
geo
(optional), object with propertieslat
andlon
-
text
: message body -
created
(optional): date/timestamp -
modified
(optional): date/timestamp -
attachments
(optional), array of objects with properties: -
type
: mime type, e.g. image/jpeg or video/mp4 -
url
: url to the content
Example
var NeverNoStory = require('../lib/never-no-story');
var story = new NeverNoStory("storyrunetest.never.no");
story.submitGenericMessage(
41, // search id
{
author: {
username: 'billg512k',
name: 'Bill Gates',
picUrl: 'http://1.vgc.no/drfront/images/2016/09/13/c=596,53,667,667;w=316;h=316;298101.jpg' // optional
},
geo: { // optional
lat: 59.9142366,
lon: 10.7530902
},
text: '640k should be enough for everyone, right?',
created: new Date(), // optional
modified: new Date(), // optional
attachments: [ // optional
{ type: 'image/jpeg', url: 'http://vg.no/annonsorinnhold/smart/uploads/covers/large_8ed01d0eaa3699f3183715aff2c749405905170a.jpg' },
{ type: 'video/mp4', url: 'http://www.w3schools.com/html/mov_bbb.mp4' }
]
})
.then(function(res)
{
console.log("OK! " + JSON.stringify(res))
},
function(err)
{
console.error("ERROR! " + err.message + ", at " + err.stack);
})