Generating synonymous, Heroku-style, server names with Lumen

Posted on April 15, 2015 | By Matt Stauffer


Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.

I gave an example yesterday about how to use Lumen, but I figured a few more examples would be fun.

If you spin up a new app on Heroku or Forge, they come up with a random name like "airy-craig" or "soaring-peaks". I figured, why don't we create a microservice that just provides these sort of names for any consuming application?

We're going to be creating our names as variations on the phrase "Happy Brad" (in honor of my dear friend Brad), and we'll use a thesaurus API to give us synonyms to the adjective we pass in. So, for example, http://www.happy-brad-naming-service.com/happy/brad would return something like:

{
    "result": "Elated Brad"
}

while http://www.happy-brad-naming-service.com/sad/brad might return something like:

{
    "result": "Depressed Brad"
}

Installing Lumen

If you haven't installed the Lumen installer yet, do that:

composer global require "laravel/lumen-installer:~1.0"

Now, just create a new Lumen project:

cd Sites
lumen new happyBrad
cd happyBrad
cp .env.example .env

Basic setup

The first thing I'll do is edit bootstrap/app.php. I'll definitely want to enabled the Dotenv::load line, and I'll be using Façades here, so I'll uncomment $app->withFacades(); as well.

Previewing your site

Now run php artisan serve and you'll be serving a site at localhost:8000. Open that up in your browser, and then jump back to your code editor.

First route

Let's edit app/Http/routes.php to set up our first route.

<?php

$app->get('/{adjective}/brad', function ($adjective) {
    return response([
        'result' => ucwords($adjective) . ' Brad'
    ]);
});

Great. We're now taking in site.com/adjective/brad and we get a JSON response of {"result": "Adjective Brad"}.

Synonyms

All we have to do now is plug in the synonym generator. I just googled "thesaurus API", and picked the Big Huge Thesaurus API. I applied for a free API key, and now I'm ready to go.

Getting the synonym

I could pull in Guzzle or write an SDK, but since this is so quick-and-dirty, let's just use file_get_contents() for now.

The URL I'm trying to create is http://words.bighugelabs.com/api/{version}/{apiKey}/{term}/json.

First, I need to save my thesaurus API key as an environment variable, so I add a line to .env and to .env.example that's THESAURUS_KEY, and in .env I'll set it equal to my actual thesaurus API key.

Second, I need to get that key in my route.

$apiKey = getenv('THESAURUS_KEY');

Now, let's construct our URL:

$url = sprintf(
    "http://words.bighugelabs.com/api/2/%s/%s/json",
    $apiKey,
    urlencode($adjective)
);

Then we can get it:

$result = json_decode(file_get_contents($url));

I know this will return something like this:

{
    "adjective": {
        "syn": [
            "felicitous",
            "glad",
            "well-chosen"
        ],
        "ant": [
            "unhappy"
        ],
        "rel": [
            "euphoric",
            "joyous"
        ],
        "sim": [
            "riant",
            "prosperous"
        ]
    }
}

So for now, I just want the array of synonyms. So, we'll pull in $result->adjective->syn.

Then, I want to randomly pull out a single adjective.

$synonyms = $result->adjective->syn;
$synonym = $synonyms[array_rand($synonyms)];

Finally, let's return our response:

return response([
    'result' => ucwords($synonym) . ' Brad'
]);

Let's put that all together:

$app->get('/{adjective}/brad', function ($adjective) {
    $apiKey = getenv('THESAURUS_KEY');

    $url = sprintf(
        "http://words.bighugelabs.com/api/2/%s/%s/json",
        $apiKey,
        urlencode($adjective)
    );

    $result = json_decode(file_get_contents($url));
    $synonyms = $result->adjective->syn;

    $synonym = $synonyms[array_rand($synonyms)];

    return response([
        'result' => ucwords($synonym) . ' Brad'
    ]);
});

Caching the response

I'm going to be hitting the API a lot here, though, so let's cache our response using Cache::remember.

$app->get('/{adjective}/brad', function ($adjective) {
    $apiKey = getenv('THESAURUS_KEY');
    // Forever cache, because synonym lists are
    // likely never going to change
    $cacheTtl = 0;

    $synonyms = Cache::remember(
        $adjective,
        $cacheTtl,
        function() use ($adjective, $apiKey)
        {
            $url = sprintf(
                "http://words.bighugelabs.com/api/2/%s/%s/json",
                $apiKey,
                urlencode($adjective)
            );

            $result = json_decode(file_get_contents($url));
            $synonyms = $result->adjective->syn;

            return $synonyms;
        }
    );

    $synonym = $synonyms[array_rand($synonyms)];

    return response([
        'result' => ucwords($synonym) . ' Brad'
    ]);
});

Check it out

You can use this tool yourself here:

http://happy-brad.fiveminutegeekshow.com/adorable/brad

And check out the code here:

https://github.com/mattstauffer/synonym-namer

And finally: If you were really using this service, A) you'd need a much bigger sample source to draw from, and B) you'd need to do much more error handling. This is just for fun.


Comments? I'm @stauffermatt on Twitter


Tags: lumen  •  laravel