LaravelLaravel & VueJsVueJs

A beautiful webapp to fetch dns records

Recently my company Spatie launched, a beautiful site to quickly lookup dns records.

True to form, we also opensourced it, here is the sourcecode on GitHub. If you want to do some dns lookups in your own app, you’ll be happy to know that we extracted the dns lookup functionalities to a package.

In this blog post I’d like to share why and how we’ve built all this.

Why create another dns lookup service?

A few weeks ago Jef, our project manager at Spatie, was asked by a client to give some dns related info. Because Jef is not a technical person. He has a fear/hate relation with the terminal. So he always delegates technical questions like those to his teammates. They just use dig to quickly get dns records. Wouldn’t it be great if Jef could do the dns lookups on his own? An idea was born.

But aren’t there already many services to perform dns lookups? Let’s ( Here are a few of the first hits:

Most of the services work, but they are really really ugly. We couldn’t find any dns lookup service that looks beautiful. So we went ahead with creating a webapp of our own.


My colleague Willem did an excellent job in making look beautiful. This is what you see when visiting the site.

No distractions like on the other sites. Just enter a domain to get some records. It couldn’t be simpler.

The results are displayed on a link which has a sharable link. You can just visit to get the dns records of Facebook.

★ READ ALSO ★  Vue.js Developer - Vue.js Jobs

If you type help you see some extra commands you can execute on our app:

Our real killer feature is of course that you can play Doom. Go on and waste some hours with this excellent game. When you’re done with that go on and drag that bookmarklet to your toolbar to lookup the dns records of the sites you visit.

Behind the scenes

We’ve open sourced the entire site. You can view the code that’s actually being deployed to our server in this repo on GitHub.

Let’s walk a bit through the code. When looking at an early version of the only controller in this project, you’ll see that everything happened inside that single controller. But because we want to easily add more commands in the features we refactored it quite a bit. In the current version the controller is quite skinny:


namespace AppHttpControllers;

use AppServicesCommandsCommandChain;
use IlluminateHttpRequest;

class HomeController extends Controller
    public function index()
        return view('home.index');

    public function submit($command = null, Request $request)
        $command = $request['command'] ?? $command;

        if (!$command) {
            return $this->index();

        return (new CommandChain())->perform(strtolower($command));

Every submitted $command is delegated to a CommandChain. Let’s take a look at the code of that CommandChain.

class CommandChain { protected $commands = [ Manual::class, Localhost::class, Clear::class, Ip::class, Doom::class, DnsLookup::class, ]; public function perform(string $command): Response { return collect($this->commands) ->map(function (string $commandClassName) { return new $commandClassName; }) ->first->canPerform($command) ->perform($command); } }

You’ll see above that we register some command classes to the chain. In perform we’ll instanciate them. The chain will ask each class: “can you perform this $command? “. The first one that can will actually perform that $command.

Let’s take a look at a such a command class. Here’s the code of the Doom command:

namespace AppServicesCommandsCommands;

use AppServicesCommandsCommand;
use SymfonyComponentHttpFoundationResponse;

class Doom implements Command
    public function canPerform(string $command): bool
        return $command === 'doom';

    public function perform(string $command): Response
        return redirect('');

The perform function of a Command class always returns are IlluminateHttpResponse. In case of the Doom command we’ll just return a redirect to a site where you can play Doom.

★ READ ALSO ★  Font Awesome component for Vue.js, using inline SVG.

Let’s take a look at another command, the DnsLookup command:

namespace AppServicesCommandsCommands;

use AppServicesCommandsCommand;
use AppServicesDnsRecordsRetriever;
use SpatieDnsDns;
use SymfonyComponentHttpFoundationResponse;

class DnsLookup implements Command
    public function canPerform(string $command): bool
        return true;

    public function perform(string $command): Response
        $dns = new Dns($command);

        $dnsRecords = $dns->getRecords();

        $domain = $dns->getDomain($command);

        if ($dnsRecords === '') {
            $errorText = __('errors.noDnsRecordsFound', compact('domain'));


            return redirect('/');

        return response()->view('home.index', ['output' => $dnsRecords, 'domain' => $domain ]);

Noticed that canPerform returns true. This command basically says, I can handle everything. If you look again $commands array in the CommandChain you’ll see that DnsLookup is registered last. So when no other Command can handle the $command the DnsLookup will do its thing.

The real magic of looking up dns records happens inside that SpatieDnsDns object which is part of our spatie/dns package.

Here’s how you can use it:

$dns = new SpatieDns('');

$dns->getRecords(); // returns all records

$dns->getRecords('A'); // returns only A records
$dns->getRecords('MX'); // returns only MX records

$dns->getRecords('A', 'MX'); // returns both A and MX records
$dns->getRecords(['A', 'MX']); // returns both A and MX records

The actual lookup of dns records inside that package is being done by calling dig, a command line tool to lookup dns related info.

Here is the relevant function inside the SpatieDnsDns class where that call happens.

protected function getRecordsOfType(string $type): string
    $command = 'dig +nocmd '.escapeshellarg($this->domain)." {$type} +multiline +noall +answer";

    $process = new Process($command);


    if (! $process->isSuccessful()) {
        throw new Exception('Dns records could not be fetched');

    return $process->getOutput();

In closing

I hope you’ve enjoyed this little behind the scenes of I’d like to emphasise that creating this service was a team effort. Every member of our team helped with making the code better. We also got some great contributions from the community for which we are grateful.

★ READ ALSO ★  Flash Vue: Learn by using Flashcards powered by Vue.js

This is not the first project that we’ve open sourced. If you like to see some more work by our team, take a look at our Dashboard, or the many Laravel, PHP and JavaScript packages we created previously. Want to support our open source efforts? Then consider, becoming a patreon.

Freek Van der Herten is a partner and developer at Spatie, an Antwerp based company that specializes in creating web apps with Laravel. After hours he writes about modern PHP and Laravel on this blog. When not coding he’s probably rehearsing with his kraut rock band. He loves waffles and butterflies.

Source link

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.