I'm trying to get a list of sites (a list of a-lists) with the Stack Exchange API using request.el
.
I'm making an Emacs major mode for Stack Exchange, so this has some nice potential payoff for you Emacs users out there. ;) (And since I tagged elisp, I'm assuming that's the lot of you.)
To do this, a fundamental necessity would be to make a request for JSON, and then view the list of returned sites. The StackExchange API supplies the /sites resource, and a request for that resource returns a collection of site objects like so:
{
"items": [
{
"site_type": "main_site",
"name": "Stack Overflow",
"logo_url": "http://cdn.sstatic.net/stackoverflow/img/logo.png",
"api_site_parameter": "stackoverflow",
"site_url": "http://stackoverflow.com",
"audience": "professional and enthusiast programmers",
"icon_url": "http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png",
"aliases": [
"http://www.stackoverflow.com"
],
"site_state": "normal",
"styling": {
"link_color": "#0077CC",
"tag_foreground_color": "#3E6D8E",
"tag_background_color": "#E0EAF1"
},
"launch_date": 1221436800,
"favicon_url": "http://cdn.sstatic.net/stackoverflow/img/favicon.ico",
"related_sites": [
{
"name": "Stack Overflow Chat",
"site_url": "http://chat.stackoverflow.com",
"relation": "chat"
}
],
"markdown_extensions": [
"Prettify"
],
"high_resolution_icon_url": "http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon@2.png"
},
{
"site_type": "main_site",
"name": "Server Fault",
"logo_url": "http://cdn.sstatic.net/serverfault/img/logo.png",
"api_site_parameter": "serverfault",
"site_url": "http://serverfault.com",
"audience": "professional system and network administrators",
"icon_url": "http://cdn.sstatic.net/serverfault/img/apple-touch-icon.png",
...
},
{
"site_type": "main_site",
"name": "Super User",
...
{
"site_type": "main_site",
"name": "Meta Stack Overflow",
...
}
...
}
I'd like to minimize the number of calls I make to the API and retrieve them all and place them in a data structure in one go for me to be able to make sense of it later on.
I'm trying to adapt one of the lovely solutions I've found here, Making JSON requests within Emacs, to fit what I need to do. It uses the request.el library, from tkf.
The example tkf gave me was able to take the most active question on a site and grab its title
and tags
properties using json-read
, which essentially turns an object into an a-list. This attempt is based off of that solution:
(request
"https://api.stackexchange.com/2.1/sites"
:parser 'buffer-string
:success (function*
(lambda (&key data &allow-other-keys)
(let* ((items (assoc-default 'items data))
(names (mapcar (lambda (item) (assoc-default 'name item)) items))
(launches (mapcar (lambda (item) (assoc-default 'launch-date item)) items)))
(mapcar* (lambda (name launch)
(message "name:`%s` launch:`%s`" name launch))
names
launches)))))
...but seems entirely ineffective. The other examples work perfectly, so it is something wrong with my usage.
request.el can be downloaded from the MELPA package repository and, to my knowledge, requires curl
to run correctly (which I have).
I suspect the problem lies in my usage (or preparation thereof) of mapcar*
, where the following does work as expected:
(mapcar* (lambda (a b) (insert a) (insert b)) '(1 2 3) '(4 5 6))
I know this post is long, but I tried to provide as much information as I could.
You were almost there. This one works for me:
(request
"https://api.stackexchange.com/2.1/sites"
:parser 'json-read
:success (function*
(lambda (&key data &allow-other-keys)
(let* ((items (assoc-default 'items data))
(names (mapcar (lambda (item) (assoc-default 'name item)) items))
(launches (mapcar (lambda (item) (assoc-default 'launch_date item)) items)))
(mapcar* (lambda (name launch)
(message "name:`%s` launch:`%s`" name launch))
names
launches)))))
Two changes: 1. use json-read
instead of buffer-string
for parser argument. 2. use launch_date
instead of launch-date
as the key for alist.