<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Luke</title>
    <description>The latest articles on DEV Community by Luke (@styxofdynamite).</description>
    <link>https://dev.to/styxofdynamite</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F291647%2F829409c8-4447-4145-baf4-31437e4a3206.jpeg</url>
      <title>DEV Community: Luke</title>
      <link>https://dev.to/styxofdynamite</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/styxofdynamite"/>
    <language>en</language>
    <item>
      <title>Marking up FAQ's with Schema.org</title>
      <dc:creator>Luke</dc:creator>
      <pubDate>Mon, 06 Sep 2021 19:03:28 +0000</pubDate>
      <link>https://dev.to/styxofdynamite/marking-up-faq-s-with-schema-org-ncd</link>
      <guid>https://dev.to/styxofdynamite/marking-up-faq-s-with-schema-org-ncd</guid>
      <description>&lt;p&gt;I recently built &lt;a href="https://www.uk-area-codes.info" rel="noopener noreferrer"&gt;UKAreaCodes.info&lt;/a&gt; as an experiement in deploying apps to Digital Ocean's App Platform.&lt;/p&gt;

&lt;p&gt;In this article I'm going to breifly explain how I utilised the Rich Snippets / Structured Data FAQ's (Frequently Asked Questions) Schema to display in SERPS.&lt;/p&gt;

&lt;p&gt;The schema amongst others is defined by &lt;a href="https://schema.org" rel="noopener noreferrer"&gt;schema.org&lt;/a&gt; and allows the following search enhancement&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An "accordion" of your question and answer directly on Googles SERP.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx496d5axrdrorbw9awq6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx496d5axrdrorbw9awq6.png" alt="FAQ Search enhancement"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To obtain this you simply need to add a JSON snippet like the example here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script type="application/ld+json"&amp;gt;
    {
        "@context": "https://schema.org",
        "@type": "FAQPage",
        "mainEntity": [{
            "@type": "Question",
            "name": "Can you find out who called me from this number?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "&amp;lt;p&amp;gt;Often we get asked whether we can identify callers by their phone number, whislt some sites offer this functionality we do not at this point, it may be added in future. We simply help you identify the geographic location the call originated from.&amp;lt;/p&amp;gt;"
            }
        }, {
            "@type": "Question",
            "name": "Why does UK Area Codes site exist?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "We created UKAreaCodes.info to help people look up area code locations for number that are calling them."
            }
        }]
    }
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>php</category>
      <category>schema</category>
    </item>
    <item>
      <title>Deploying a "serverless" app</title>
      <dc:creator>Luke</dc:creator>
      <pubDate>Wed, 18 Aug 2021 16:05:41 +0000</pubDate>
      <link>https://dev.to/styxofdynamite/deploying-a-serverless-app-3fa0</link>
      <guid>https://dev.to/styxofdynamite/deploying-a-serverless-app-3fa0</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;So last night I decided to deploy a serverless app that generates some number of random words.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Services
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Route53&lt;/li&gt;
&lt;li&gt;Lambda&lt;/li&gt;
&lt;li&gt;API Gateway&lt;/li&gt;
&lt;li&gt;S3 Storage&lt;/li&gt;
&lt;li&gt;Cloudfront Cache&lt;/li&gt;
&lt;li&gt;Certificate Manager&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First up, this isn't a tutorial as there are plenty of those about and I wanted to share a more high level description of the various AWS services used and how they all linked together in my example deployment.&lt;/p&gt;

&lt;p&gt;So first off the example app, its a very simple react app that takes a user given number of random words to return and a time setting as to how frequently those words should be updated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0vg89ezrd86fjq2e14e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0vg89ezrd86fjq2e14e.png" alt="JustRandom.net"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This react app is deployed at &lt;a href="//justrandom.net"&gt;justrandom.net&lt;/a&gt; a domain name configured via &lt;strong&gt;Route53&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This app is being served from an &lt;strong&gt;S3 Bucket&lt;/strong&gt;, via &lt;strong&gt;Cloudfront&lt;/strong&gt; using an AWS managed SSL Certificate.&lt;/p&gt;

&lt;p&gt;When the app is set to fetch some random words, every 5, 15 or 30 seconds, it sends a request to an &lt;strong&gt;API Gateway&lt;/strong&gt; this request is then passed to a &lt;strong&gt;Lambda&lt;/strong&gt; function, which is written in Javascript.&lt;/p&gt;

&lt;p&gt;This &lt;strong&gt;Lambda&lt;/strong&gt; function returns a JSON response containing the requested number of random words back to the &lt;strong&gt;API Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is then returned to the waiting react app, and all in less than 40ms in most cases!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>react</category>
      <category>api</category>
    </item>
    <item>
      <title>Adding a dynamic favicon with users scroll percentage</title>
      <dc:creator>Luke</dc:creator>
      <pubDate>Wed, 16 Dec 2020 14:53:28 +0000</pubDate>
      <link>https://dev.to/styxofdynamite/adding-a-dynamic-favicon-with-users-scroll-percentage-26mp</link>
      <guid>https://dev.to/styxofdynamite/adding-a-dynamic-favicon-with-users-scroll-percentage-26mp</guid>
      <description>&lt;p&gt;&lt;a href="https://styxofdynamite.github.io/50days50projects/percentage-scroll/" rel="noopener noreferrer"&gt;See the effect here&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx6wohgyw2lbmee657vy5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx6wohgyw2lbmee657vy5.png" alt="Favicon Scroll"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I decided to set myself the challenge of updating a favicon dynamically to show the users percentage scroll through the page.&lt;/p&gt;

&lt;p&gt;First up, we introduce a function to generate an SVG as a data URL (which we will use for the favicon)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const faviconHref = (value) =&amp;gt; {
    return `data:image/svg+xml,&amp;lt;svg xmlns=%22http://www.w3.org/2000/svg%22 width=%22256%22 height=%22256%22 viewBox=%220 0 75 75 %22 fill=%22white%22&amp;gt;&amp;lt;text x=%2250%%22 y=%2250%%22 dominant-baseline=%22central%22 text-anchor=%22middle%22 font-size=%2258%22 stroke=%22black%22 fill=%22white%22&amp;gt;${value}&amp;lt;/text&amp;gt;&amp;lt;/svg&amp;gt;`;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function will take an input value and return a corresponding SVG (as a data URL) with the "value" text drawn on it.&lt;/p&gt;

&lt;p&gt;The next step is to introduce a function to update the favicon in the page header.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const changeFavicon = (favicon) =&amp;gt; {
    if (typeof window === 'undefined') {
        return;
    }
    const link = window.document.querySelector("link[rel*='icon']") || window.document.createElement('link');
    link.type = 'image/svg+xml';
    link.rel = 'shortcut icon';
    link.href = faviconHref(favicon);

    window.document.getElementsByTagName('head')[0].appendChild(link);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we introduce a function to calculate the users sroll and change the favicon using the above functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const calculateScroll = () =&amp;gt; {
    const parent = document.body.parentNode;
    let percentage =
        ((document.body.scrollTop || parent.scrollTop) /
            (parent.scrollHeight - parent.clientHeight)) *
        100;

    percentage = Math.round(percentage);

    changeFavicon(percentage);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are calculating the users scroll percentage of distance down the page and passing that percentage into the changeFavicon function, which in turns renders an SVG of the passed percentage value.&lt;/p&gt;

&lt;p&gt;Finally we need to attach a window Event Listener that will call our calculateScroll function when a users scrolls as well as make an initial call to the function when the script is loaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.addEventListener('scroll', calculateScroll);

//  initial call

calculateScroll();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above functions can be added to an HTML page, such that when a user scrolls it will update the favicon&lt;/p&gt;

</description>
      <category>favicon</category>
      <category>javascript</category>
      <category>html</category>
    </item>
    <item>
      <title>Streaming large file downloads in Laravel.</title>
      <dc:creator>Luke</dc:creator>
      <pubDate>Fri, 13 Dec 2019 11:04:13 +0000</pubDate>
      <link>https://dev.to/styxofdynamite/streaming-large-file-downloads-in-laravel-2nne</link>
      <guid>https://dev.to/styxofdynamite/streaming-large-file-downloads-in-laravel-2nne</guid>
      <description>&lt;h4&gt;
  
  
  Background
&lt;/h4&gt;

&lt;p&gt;In my role as a developer at Reviews.io we often have customers who want to export large datasets from our Dashboard. Large dynamic file downloads can be problematic as they introduce the scope for memory exhaustion.&lt;/p&gt;

&lt;p&gt;One way in which we tackle this issue is by streaming our file downloads using Laravel's Response Streaming.&lt;/p&gt;

&lt;h4&gt;
  
  
  Streamed Downloads
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Sometimes you may wish to turn the string response of a given operation into a downloadable response without having to write the contents of the operation to disk. You may use the streamDownload method in this scenario. This method accepts a callback, file name, and an optional array of headers as its arguments&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  The code
&lt;/h4&gt;

&lt;p&gt;Let's start by declaring a route to get our download file from, I've opted to make the file retrievable by making a get request to &lt;code&gt;/download&lt;/code&gt; with an optional number of rows we want the file to contain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

Route::get('download/{rows?}', ['uses' =&amp;gt; 'StreamedDownloadController@download']);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to implement our Controller Method &lt;code&gt;download&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;N.B. I'm using &lt;a href="https://github.com/fzaninotto/Faker"&gt;Faker&lt;/a&gt; here to generate the data, in reality this would be fetched from a database but the idea is essentially the same.&lt;/p&gt;

&lt;p&gt;First of we need to define the method on our controller.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Faker;

class StreamedDownloadController extends Controller
{
    public function download($rows = 50000)
    {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've specified a default value for the number of rows we want to write out to the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;        &lt;span class="c1"&gt;// callback function that writes to php://output&lt;/span&gt;
        &lt;span class="nv"&gt;$callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Open output stream&lt;/span&gt;
        &lt;span class="nv"&gt;$handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'php://output'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Add CSV headers&lt;/span&gt;
        &lt;span class="nb"&gt;fputcsv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'Name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'Address'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="c1"&gt;// Generate a faker instance&lt;/span&gt;
        &lt;span class="nv"&gt;$faker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Faker\Factory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// add the given number of rows to the file.&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$rows&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="nv"&gt;$row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="nv"&gt;$faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nv"&gt;$faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="nb"&gt;fputcsv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$row&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;


        &lt;span class="c1"&gt;// Close the output stream&lt;/span&gt;
        &lt;span class="nb"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$handle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the callback method that will process writing the file out to the &lt;code&gt;php:output&lt;/code&gt; buffer.&lt;/p&gt;

&lt;p&gt;Next up we specify the Content-Type so that the browser knows what format the file is supposed to be in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// build response headers so file downloads.&lt;/span&gt;
    &lt;span class="nv"&gt;$headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'text/csv'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally we return a &lt;code&gt;streamDownload()&lt;/code&gt; response, that executes the callback, writing the generated file out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// return the response as a streamed response.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;streamDownload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'download.csv'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$headers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>php</category>
      <category>file</category>
      <category>download</category>
    </item>
  </channel>
</rss>
