Example: Recent News
As our first example, we'll tackle a common question: how do I simply get a news feed?
Background Information
In Apollo, news feeds are represented as Channels, which are JSON expressions that allow you to define simple or complex filters on news content. Channels can define streams of content that produce thousands of documents per day, or a single document out of our billions stored. They can contain a single filter, or even hundreds. Channels are versatile objects that form the core of how to build Apollo Pro® news and content into your workflows.
In this example, our goal is to simply fetch recent news for a pre-defined channel. We'll accomplish this by chaining together two API requests: the first to read the detailed definition of a stored channel, and a second which uses that channel definition to pull recent news.
Building the Requests
Authenticating
First, we need to authenticate with the API. Please see the page on Authentication. You will need an access token in order to authenticate the following requests.
Fetching the Channel
Now that we're authenticated, the next step is to fetch the channel definition. Channels are identified using their
distinct IDs. For this example, we'll be using channel 233
, which is configured to return high-quality, financial
services news content. This will work for any channel that is set to public or owned by you.
The endpoint we need to use is GET /channel/id/{channelID}
. Looking at the associated information in the
OpenAPI/Swagger reference page, we see that all we need is to supply the
channel ID parameter. So, we come up with the following request:
Request
curl --location --request GET 'https://global-api.fintechstudios.com/v1/channel/id/233' \
--header 'x-api-key: <key>' \
--header 'Authorization: Bearer <token>' \
--data-raw ''
GET /v1/channel/id/233 HTTP/1.1
Host: global-api.fintechstudios.com
x-api-key: <key>
:
Authorization: Bearer <token>
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
Request request = new Request.Builder()
.url("https://global-api.fintechstudios.com/v1/channel/id/233")
.method("GET", null)
.addHeader("x-api-key", "<key>")
.addHeader("Authorization", "Bearer <token>")
.build();
Response response = client.newCall(request).execute();
var request = require('request');
var options = {
'method': 'GET',
'url': 'https://global-api.fintechstudios.com/v1/channel/id/233',
'headers': {
'x-api-key': '<key>',
'': '',
'Authorization': 'Bearer <token>'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://global-api.fintechstudios.com/v1/channel/id/233',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => array(
'x-api-key: <key>',
'Authorization: Bearer <token>'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
import http.client
conn = http.client.HTTPSConnection("global-api.fintechstudios.com")
payload = ''
headers = {
'x-api-key': '<key>',
'Authorization': 'Bearer <token>'
}
conn.request("GET", "/v1/channel/id/233", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
The response will be an array of channel objects containing the channel definition we requested:
Response
{
"channels": [
{
"owner": "",
"subscriber_count": 1,
"subscribers": [],
"created": "2017-12-26T20:50:31.478Z",
"updated": "2017-12-26T20:50:31.478Z",
"public": true,
"name": "FTS Curated News",
"description": "The default FTS news feed, with some basic filters applied.",
"id": 233,
"stages": [
{
"not": false,
"entities": [
{
"type": "entity",
"value": "13512"
}
]
},
{
"not": false,
"entities": [
{
"type": "entity",
"value": "13579"
}
]
},
{
"not": false,
"entities": [
{
"type": "entity",
"value": "14613"
},
{
"type": "entity",
"value": "750861"
}
]
}
]
}
]
}
The top fields, just as created
, updated
, name
and id
are all metadata fields for the channel, while the
contents of stages
contains the filter definition.
This channel has three stage items in the stages
field:
Warning
You should make sure you're familiar with creating and managing channels.
- The first selects any documents that are tagged with entity ID
13512
, which is the topic Major Corporate News. This means that all stories in this channel will need to contain this tag. - The next stage selects any documents that are tagged with entity ID
13579
, which is the topic Financial. This means that all stories in this channel will also need to contain this tag, in addition to Major Corporate News. - The final stage contains two entities
14613
and750861
, which are the feed categories Major News Publications and Highly Ranked Sources, respectively. Since these two items are in the same channel stage, it means that any document that contains one of more of these two entities will pass.
The stages
object is the important piece, so let's save that for our next step.
Requesting News
Tip
You can easily retrieve a user ID from your access token. Simply inspect the JWT token using a tool like
JWT.io, and look at the sub
(Subject) field.
The next step is to use the stages
in order to request relevant news. The endpoint we need to use is
POST /news/user/{userId}/query
. The only required parameter is {userId}
, but we'll also want to include the
stages
body parameter. For detailed request options, you'll want to visit the
OpenAPI/Swagger reference page.
Using the stages
data from before, we can create the following API request:
Request
curl --location --request POST 'https://global-api.fintechstudios.com/v1/news/user/<userId>/query' \
--header 'x-api-key: <key>' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data-raw '{
"stages": [
{
"not": false,
"entities": [
{
"type": "entity",
"value": "13512"
}
]
},
{
"not": false,
"entities": [
{
"type": "entity",
"value": "13579"
}
]
},
{
"not": false,
"entities": [
{
"type": "entity",
"value": "14613"
},
{
"type": "entity",
"value": "750861"
}
]
}
]
}'
POST /v1/news/user/<userId>/query HTTP/1.1
Host: global-api.fintechstudios.com
x-api-key: <key>
Authorization: Bearer <token>
Content-Type: application/json
{
"stages": [
{
"not": false,
"entities": [
{
"type": "entity",
"value": "13512"
}
]
},
{
"not": false,
"entities": [
{
"type": "entity",
"value": "13579"
}
]
},
{
"not": false,
"entities": [
{
"type": "entity",
"value": "14613"
},
{
"type": "entity",
"value": "750861"
}
]
}
]
}
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\"stages\":[{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"13512\"}]},{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"13579\"}]},{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"14613\"},{\"type\":\"entity\",\"value\":\"750861\"}]}]}");
Request request = new Request.Builder()
.url("https://global-api.fintechstudios.com/v1/news/user/<userId>/query")
.method("POST", body)
.addHeader("x-api-key", "<key>")
.addHeader("", "")
.addHeader("Authorization", "Bearer <token>")
.addHeader("Content-Type", "application/json")
.build();
Response response = client.newCall(request).execute();
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://global-api.fintechstudios.com/v1/news/user/<userId>/query',
'headers': {
'x-api-key': '<key>',
'Authorization': 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({"stages":[{"not":false,"entities":[{"type":"entity","value":"13512"}]},{"not":false,"entities":[{"type":"entity","value":"13579"}]},{"not":false,"entities":[{"type":"entity","value":"14613"},{"type":"entity","value":"750861"}]}]})
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://global-api.fintechstudios.com/v1/news/user/<userId>/query',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>'{
"stages": [
{
"not": false,
"entities": [
{
"type": "entity",
"value": "13512"
}
]
},
{
"not": false,
"entities": [
{
"type": "entity",
"value": "13579"
}
]
},
{
"not": false,
"entities": [
{
"type": "entity",
"value": "14613"
},
{
"type": "entity",
"value": "750861"
}
]
}
]
}',
CURLOPT_HTTPHEADER => array(
'x-api-key: <key>',
'Authorization: Bearer <token>',
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
import http.client
conn = http.client.HTTPSConnection("global-api.fintechstudios.com")
payload = "{\"stages\":[{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"13512\"}]},{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"13579\"}]},{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"14613\"},{\"type\":\"entity\",\"value\":\"750861\"}]}]}"
headers = {
'x-api-key': '<key>',
'Authorization': 'Bearer <token>',
'Content-Type': 'application/json'
}
conn.request("POST", "/v1/news/user/<userId>/query", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
The response will be an array of article objects and result metadata, looking something like this:
Response
{
"articles": [
{
"id": 1274021709,
"title": "Renewed tax break for Arizona angel investors heads to Ducey’s desk",
"summary": "The angel investment tax credit bill passed both chambers of the Arizona legislature just as the session came to a close, and the governor is expected to sign it into law this week. See what Arizona startups have benefited from the program in the past.",
"url": "https://www.bizjournals.com/phoenix/news/2021/07/06/angel-tax-credit-10-year-20-million-extension.html?ana=RSS&s=article_search&utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+bizj_phoenix+%28Phoenix+Business+Journal%29",
"published": "2021-07-06T16:35:44.000Z",
"updated": "2021-07-06T16:35:44.000Z",
"created_at": "2021-07-06T16:35:50.166Z",
"updated_at": "2021-07-06T16:36:01.062Z",
"source": 103593,
"contributor": 103594,
"author": 0,
"headline_cluster": "lzh3fPDLafPV3IRhptshOwonGSY8C5t+Hj0o0G/gBLs=",
"url_cluster": "Na4DEEID8DoGTPdLB2c2bmfmLYgl+HecZrwlNi6ZU/8=",
"entities": [
2307607,
2307504,
8857455,
84590,
...
],
"primary_entities": [
84564,
13513,
13512,
2,
14629,
750862,
...
],
"secondary_entities": [
2307607,
2307504,
8857455,
...
],
"tertiary_entities": [
84590,
1949690,
13502,
...
],
"image_url": "https://media.bizj.us/view/img/4834571/page10arizonacapitol*100xx1198-1200-301-0.jpg",
"metadata": {
"docSummary": {
"type": "text",
"values": [
"The angel investment tax credit bill passed both chambers of the Arizona legislature just as the session came to a close, and the governor is expected to sign it into law this week."
]
}
},
"verifications": {},
"score": 1.4969288
},
...
],
"hits": {
"to": 1625597514019,
"clusterCountMap": {
"lzh3fPDLafPV3IRhptshOwonGSY8C5t+Hj0o0G/gBLs=": 1,
"tz1gyFR3vElhTNI36RDuWeDplYLoFwWFCdpEyW4vOGk=": 3,
"uDyTiylW9+Dc3fRL2nN/RnbUF0YVf0P7/wF11Go4Bts=": 1,
"21wCyN9b2iRNjmtnptQh/OTlrIwn7DZSEa90zcXUCVE=": 1,
"ttbSS3gtayywefKfXWKlDEf80yznxEU8IM18yU6XSUQ=": 9,
"MKIy3SfFkbGQ1a2OH0vvTv0bIRhpGQbHTqfOUo+vE6I=": 1,
...
},
"count": 9950,
"hiddenCount": 0,
"clusterCount": 0,
"from": 1625097600000
},
"hiddenClusterMap": {},
"articleWorkflowStates": []
}
The results about were truncated, but are representative of what you should expect from the output.
Next Steps
For next steps, try modifying your news request to account for the following:
- A different public channel
- A private channel owned by the requesting user
- A channel with more or fewer filters.