fortuned
implements an HTTP API for retrieving fortune cookies, as normally
shown by the fortune
programme on your computer. This allows access to these
cookies via your favorite web services. Because.
Yadda yadda leveraging yadda industry-grade yadda yadda RESTful yadda disruptive yadda yadda revenue yadda killer app yadda convergence yadda robust metrics yadda yadda game-changing. This paragraph was placed here in case you need to win a round of buzzword bingo.
A hosted version of this API is available at https://api.ef.gy/fortune, and the examples here will refer to that base URL.
The API server is also available through a Tor Hidden Service at
http://664ov6iyvgpe63xn.onion/fortune - if you wish to use this service instead
of the regular one, just change the URLs below accordingly. This means your
curl
programme needs to be set up for Tor access, of course.
Otherwise, you can play along at home with this JSFiddle: https://jsfiddle.net/jyujin/t87whwjr/62/
The /fortune
endpoint looks up a random fortune cookie and returns it as the
resource body of the request. This method will always reply with a code 307
and a Location
header which points to the canonical URL for the cookie.
The body of the response still includes the same content you'd get by following the redirect, as those are fairly short and there didn't seem to be a need to complicate things further.
If you requested this resource, like so:
curl https://api.ef.gy/fortune
The reply you get should be something like this (the actual cookie is chosen at random):
Better living a beggar than buried an emperor.
This is the most straightforward use of the API possible: get a random fortune
cookie, no thrills, no strings attached. In fact, if you're on OSX (or didn't
feel like installing fortune
for some other reason), you can just stick this
in your .profile
:
alias fortune="curl https://api.ef.gy/fortune"
And now you don't need to install fortune
anymore, you can just use this.
Happyness.
Like /fortune
but you get to specify the ID number of the cookie. This is
nice for linking to specific fortune cookies, as one might want to. This is also
how the /fortune
endpoint points to a canonical URL in its Location
header.
IDs are not necessarily stable over time, as they depend on the loading order of the cookies, which may change over time. It is usually stable, however.
Assuming you wanted to fetch whatever cookie has ID #42, you could run this command:
curl https://api.ef.gy/fortune/42
And you might get a result such as this one:
At ebb tide I wrote a line upon the sand, and gave it all my heart and all
my soul. At flood tide I returned to read what I had inscribed and found my
ignorance upon the shore.
-- Kahlil Gibran
These links are usually stable for short-ish intervals, but they may still change over time.
The server supports output in plain text, XML and JSON formats. You select which
of the three you want by providing a valid Accept
header using the correct
MIME type of the format you want:
text/plain
selects plain text, and is the default if none is specified (for the benefit ofcurl
users).text/json
selects JSON output.text/xml
andapplication/xml
select XML output.
Format selection works for both the /fortune
and the /fortune/*ID*
endpoints, and indeed the output of the two is the same for the same cookie.
The JSON format is a top-level object with these fields:
cookie
, the actual fortune cookie itself.file
, the source file of the cookie.file-id
, the sequence number of the cookie in thefile
.id
, the global ID of the cookie.
file
and file-id
are purely informative, though you could use this
information to look up the cookie in a local copy of the file.
Like the JSON format, this one is pretty straightforward. It's a simple XML
document, with one <fortune/>
element. The namespace is set as
http://ef.gy/2012/fortune
, as one does not simply create an XML document
without a namespace.
The cookie itself is the text content of this element, and it has the following attributes:
sourceFile
, which is the local path the cookie was read from.fileID
, the sequence number of the cookie in this file.id
, the global ID of this cookie.
See below for an example of this in actual usage.
If we run curl
with header output enabled...
curl -i https://api.ef.gy/fortune
We see that the server announces that it does actually check the Accept
header
and will vary its output accordingly:
HTTP/1.1 307 Temporary Redirect
Server: nginx/1.6.2
Date: Sun, 04 Jun 2017 16:22:58 GMT
Content-Type: text/plain
Content-Length: 70
Connection: keep-alive
Location: /fortune/12814
Vary: Accept
Strict-Transport-Security: max-age=10886400; includeSubDomains; preload
Booker's Law:
An ounce of application is worth a ton of abstraction.
Also note the Location
header while you're at it, and the 307
status code
for the /fortune
endpoint.
Assume we wanted to use this API in a shiny AJAX application. To do so, we'd naturally want JSON output:
curl -i https://api.ef.gy/fortune -H 'Accept: text/json'
This produces a result much like this one:
HTTP/1.1 307 Temporary Redirect
Server: nginx/1.6.2
Date: Mon, 05 Jun 2017 11:31:36 GMT
Content-Type: text/json
Content-Length: 153
Connection: keep-alive
Location: /fortune/11833
Vary: Accept
Strict-Transport-Security: max-age=10886400; includeSubDomains; preload
Access-Control-Allow-Origin: *
{"cookie":"I'm a Hollywood writer; so I put on a sports jacket and take off my brain.\n","file":"/usr/share/games/fortunes/art","file-id":155,"id":11833}
As mentioned before, this also works when given an ID:
curl -i https://api.ef.gy/fortune/666 -H 'Accept: text/json'
Which results in...
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Mon, 05 Jun 2017 11:30:45 GMT
Content-Type: text/json
Content-Length: 271
Connection: keep-alive
Vary: Accept
Strict-Transport-Security: max-age=10886400; includeSubDomains; preload
Access-Control-Allow-Origin: *
{"cookie":"<NeonKttn> I had a friend stick me in her closet during highschool beacuse I\n wouldn't believe that her boyfriend knew about foreplay...\n<NeonKttn> I shoulda brought popcorn. :)\n","file":"/usr/share/games/fortunes/knghtbrd","file-id":167,"id":666}
If you're feeling particularly much like punishing yourself, here's an example of the XML output, which you would retrieve like this:
curl https://api.ef.gy/fortune -H 'Accept: text/xml'
... and which would result in...
<?xml version='1.0' encoding='utf-8'?><fortune xmlns='http://ef.gy/2012/fortune' sourceFile='/usr/share/games/fortunes/politics' fileID='207' id='1786'><![CDATA[I was appalled by this story of the destruction of a member of a valued
endangered species. It's all very well to celebrate the practicality of
pigs by ennobling the porcine sibling who constructed his home out of
bricks and mortar. But to wantonly destroy a wolf, even one with an
excessive taste for porkers, is unconscionable in these ecologically
critical times when both man and his domestic beasts continue to maraud
the earth.
Sylvia Kamerman, "Book Reviewing"
]]></fortune>
It's fairly readable XML, but it's still XML.
You can compile and run fortuned
yourself, all you need is a C++14-compatible
compiler and libc on a UNIX-like OS. The instructions for CXXHTTP should get you
started with any dependencies you need: https://github.com/ef-gy/cxxhttp
In addition to those listed there, you'll also need some fortune cookie files. Installing fortune-mod and a few of the fortune packs should take care of that.