<?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: Eka</title>
    <description>The latest articles on DEV Community by Eka (@ekafyi).</description>
    <link>https://dev.to/ekafyi</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%2F70827%2F319e1725-cd9c-40c5-bbad-6e9be00879be.png</url>
      <title>DEV Community: Eka</title>
      <link>https://dev.to/ekafyi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ekafyi"/>
    <language>en</language>
    <item>
      <title>First impressions on Next.js Automatic Font Optimization</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Sat, 01 May 2021 08:49:17 +0000</pubDate>
      <link>https://dev.to/ekafyi/first-impressions-on-next-js-automatic-font-optimization-32a1</link>
      <guid>https://dev.to/ekafyi/first-impressions-on-next-js-automatic-font-optimization-32a1</guid>
      <description>Cover photo: Lobster by &lt;a href="https://unsplash.com/photos/OJPBfUqgsRU"&gt;Meritt Thomas&lt;/a&gt;




&lt;p&gt;&lt;strong&gt;Automatic Webfont Optimization&lt;/strong&gt; is a new feature that shipped with &lt;a href="https://nextjs.org/blog/next-10-2#automatic-webfont-optimization"&gt;Next.js 10.2&lt;/a&gt;. I tried it fresh off the grill, and here is what I think.&lt;/p&gt;




&lt;h3&gt;
  
  
  Misnomer (for now)
&lt;/h3&gt;

&lt;p&gt;Despite the name, currently it only works for Google Fonts loaded from &lt;code&gt;fonts.googleapis.com&lt;/code&gt;. It does not work with other sources, including eg. mirrored Google fonts in &lt;a href="https://www.labsterx.com/blog/things-to-consider-when-building-a-website-in-china-9-shtml/"&gt;regions that block Google domains&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As per &lt;a href="https://nextjs.org/blog/next-10-2#automatic-webfont-optimization"&gt;their blog post&lt;/a&gt;, they will add integration with other font providers in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use it?
&lt;/h3&gt;

&lt;p&gt;Add a &lt;code&gt;link&lt;/code&gt; tag that loads the Google fonts CSS to Next.js’ built-in &lt;code&gt;Head&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;MyPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt;
          &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Lobster"&lt;/span&gt;
          &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello world!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;



&lt;p&gt;&lt;code&gt;Head&lt;/code&gt; is a special component that enables us to append the HTML &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element from our page components or from the custom &lt;code&gt;Document&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;More info: &lt;a href="https://nextjs.org/docs/api-reference/next/head"&gt;next/head&lt;/a&gt; | &lt;a href="https://nextjs.org/docs/advanced-features/custom-document"&gt;next/document&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How does it work?
&lt;/h3&gt;

&lt;p&gt;Our code above is compiled into this on build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- ... other head/meta tags --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;data-href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Lobster"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style &lt;/span&gt;&lt;span class="na"&gt;data-href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Lobster"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;@font-face&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;'Lobster'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sx"&gt;url(https://fonts.gstatic.com/s/lobster/v23/neILzCirqoswsqX9zoKmM4MwWJU.woff2)&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'woff2'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="py"&gt;unicode-range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0000-00&lt;/span&gt;&lt;span class="n"&gt;FF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0131&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0152-0153&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;&lt;span class="n"&gt;BB-02BC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;&lt;span class="n"&gt;C6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;&lt;span class="n"&gt;DA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;&lt;span class="n"&gt;DC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2000-206&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2074&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="n"&gt;AC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2122&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2191&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2193&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2215&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="n"&gt;FEFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="n"&gt;FFFD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without optimization:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the &lt;code&gt;link&lt;/code&gt; tag loads the Google fonts CSS, &lt;code&gt;https://fonts.googleapis.com/css2?family=Lobster&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the CSS &lt;code&gt;@font-face&lt;/code&gt; loads the actual font source, &lt;code&gt;https://fonts.gstatic.com/s/lobster/v23/neILzCirqoswsqX9zoKmM4MwWJU.woff2&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With optimization, we skip step (1). Notice that the &lt;code&gt;href&lt;/code&gt; attribute is changed into &lt;code&gt;data-href&lt;/code&gt;. Instead, the style declarations are inlined and injected to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. The browser requests the font file(s) in step (2) directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why use it?
&lt;/h3&gt;

&lt;p&gt;If you use Lighthouse, you may have come across the recommendation to &lt;a href="https://web.dev/render-blocking-resources/"&gt;eliminate render-blocking resources&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When we use the original &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag, the browser &lt;em&gt;pauses&lt;/em&gt; to request the URL in the &lt;code&gt;href&lt;/code&gt; attribute, eg. &lt;code&gt;https://fonts.googleapis.com/css2?family=Lobster&lt;/code&gt;. When it succeeds or fails, it continues rendering the rest of the page.&lt;/p&gt;

&lt;p&gt;The font files declared in the &lt;code&gt;@font-face&lt;/code&gt; CSS itself, eg. &lt;code&gt;https://fonts.gstatic.com/s/lobster/v23/neILzCirqoswsqX9zoKmM4MwWJU.woff2&lt;/code&gt;, are loaded asynchronously. They &lt;em&gt;don't block&lt;/em&gt; the rendering process.&lt;/p&gt;

&lt;p&gt;By using inlined style, we eliminate this render-blocking instance, thus improving page performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best paired with...
&lt;/h3&gt;

&lt;p&gt;Add these for optimal results.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;preconnect&lt;/code&gt; to the font host origin
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"preconnect"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.gstatic.com"&lt;/span&gt; &lt;span class="na"&gt;crossOrigin&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We tell the browser that we &lt;em&gt;intend to connect&lt;/em&gt; to &lt;code&gt;fonts.gstatic.com&lt;/code&gt; and retrieve our font file (&lt;code&gt;https://fonts.gstatic.com/s/lobster/v23/neILzCirqoswsqX9zoKmM4MwWJU.woff2&lt;/code&gt;) from there.&lt;/p&gt;

&lt;h4&gt;
  
  
  Add display=swap to prevent FOUT
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt;
  &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Lobster&amp;amp;display=swap"&lt;/span&gt;
  &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I mentioned above that font files load asynchronously. It does not block rendering (yay), but it could mean a &lt;em&gt;"flash of invisible text"&lt;/em&gt; (oh no) when the text content is rendered before the font file finishes loading. Adding &lt;code&gt;display=swap&lt;/code&gt; renders the text with the available fallback font, then &lt;em&gt;swaps&lt;/em&gt; it with the intended web font once it finishes loading.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveats
&lt;/h3&gt;

&lt;p&gt;🔮 &lt;em&gt;Future readers: This post is written three days after the public launch. Things described here may have changed when you read this.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Be aware of these possible issues if using this in production.&lt;/p&gt;

&lt;h4&gt;
  
  
  Issue 1: Does not fire on client-side navigation change
&lt;/h4&gt;

&lt;p&gt;When using client-side navigation, such as when using Next.js &lt;code&gt;Link&lt;/code&gt; component, the &lt;code&gt;style&lt;/code&gt; tag is &lt;em&gt;not&lt;/em&gt; injected into the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; in the destination route. This causes issue if we use different fonts in each page route component.&lt;/p&gt;

&lt;p&gt;For example, we have &lt;a href="https://example-nextjs-webfont-optimization.vercel.app"&gt;Page A&lt;/a&gt; that uses the &lt;em&gt;Permanent Marker&lt;/em&gt; handwriting typeface and &lt;a href="https://example-nextjs-webfont-optimization.vercel.app/hello-lobster"&gt;Page B&lt;/a&gt; that uses the legendary &lt;em&gt;Lobster&lt;/em&gt; typeface. Accessing either page directly works fine. Click on those pages and you'll see the respective typefaces.&lt;/p&gt;

&lt;p&gt;But try navigating to Page A from &lt;a href="https://example-nextjs-webfont-optimization.vercel.app/hello-lobster"&gt;Page B&lt;/a&gt; by clicking the &lt;em&gt;"go back"&lt;/em&gt; link. Page A is rendered with the default typeface instead of &lt;em&gt;Permanent Marker&lt;/em&gt;. If you open DevTools, you'll see that Page A's font stylesheet is &lt;em&gt;not&lt;/em&gt; injected into the &lt;code&gt;head&lt;/code&gt;, so the font file is not loaded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Load all fonts in the &lt;a href="https://nextjs.org/docs/advanced-features/custom-document"&gt;custom Document&lt;/a&gt; &lt;code&gt;Head&lt;/code&gt; instead of in page routes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ DON’T: Load different fonts in page components 

&lt;ul&gt;
&lt;li&gt;code: &lt;a href="https://github.com/ekafyi/example-nextjs-webfont-optimization/blob/main/pages/index.tsx#L16-L19"&gt;https://github.com/ekafyi/example-nextjs-webfont-optimization/blob/main/pages/index.tsx#L16-L19&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;preview: &lt;a href="https://example-nextjs-webfont-optimization.vercel.app/hello-lobster"&gt;https://example-nextjs-webfont-optimization.vercel.app/hello-lobster&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;👍🏽 DO: Load fonts in custom _document

&lt;ul&gt;
&lt;li&gt;code: &lt;a href="https://github.com/ekafyi/example-nextjs-webfont-optimization/blob/with-custom-document/pages/_document.tsx#L26-L29"&gt;https://github.com/ekafyi/example-nextjs-webfont-optimization/blob/with-custom-document/pages/_document.tsx#L26-L29&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;preview: &lt;a href="https://example-nextjs-webfont-optimization-e0t88ypsc-ekafyi.vercel.app/hello-lobster"&gt;https://example-nextjs-webfont-optimization-e0t88ypsc-ekafyi.vercel.app/hello-lobster&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Issue 2: Stops working arbitrarily
&lt;/h4&gt;

&lt;p&gt;The first time I used this feature, it &lt;em&gt;did&lt;/em&gt; work and rendered this code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;data-href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Lobster"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style &lt;/span&gt;&lt;span class="na"&gt;data-href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Lobster"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;@font-face&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;'Lobster'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, in subsequent builds it renders this instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;data-href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Lobster"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Lobster"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of inlining the style, now it only duplicates the render-blocking stylesheet link tag. In addition to checking the &lt;code&gt;head&lt;/code&gt; tag from the DevTools, running a &lt;a href="https://lighthouse-dot-webdotdevsite.appspot.com//lh/html?url=https%3A%2F%2Fexample-nextjs-webfont-optimization-1fe1cxpz6-ekafyi.vercel.app%2F"&gt;Lighthouse test&lt;/a&gt; gives me an &lt;em&gt;"Eliminate render-blocking resources"&lt;/em&gt; warning, which confirms that font optimization has indeed stopped working.&lt;/p&gt;

&lt;p&gt;I managed to reproduce this in a fresh repo from one of the official examples, but was not able to pinpoint the cause. The commits/builds that triggered and fixed the issue were completely unrelated, eg. adding a new page and removing a favicon. Reverting the offending changes did not affect the font optimization issue.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;commit &lt;a href="https://github.com/ekafyi/example-nextjs-webfont-optimization/commit/46568966da0d6d99aa9a275c2205be662b679092"&gt;4656896&lt;/a&gt; — font optimization works

&lt;ul&gt;
&lt;li&gt;preview: &lt;a href="https://example-nextjs-webfont-optimization-2yi6vsuvr-ekafyi.vercel.app/"&gt;https://example-nextjs-webfont-optimization-2yi6vsuvr-ekafyi.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;commit &lt;a href="https://github.com/ekafyi/example-nextjs-webfont-optimization/commit/d8d9735710e05fdde5ff7f13b994bff841354e9c"&gt;d8d9735&lt;/a&gt; — font optimization does not work

&lt;ul&gt;
&lt;li&gt;preview: &lt;a href="https://example-nextjs-webfont-optimization-1fe1cxpz6-ekafyi.vercel.app/"&gt;https://example-nextjs-webfont-optimization-1fe1cxpz6-ekafyi.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;commit &lt;a href="https://github.com/ekafyi/example-nextjs-webfont-optimization/commit/589b900f7e19af9d4f1e41c37ec3f68bb38f56aa"&gt;589b900&lt;/a&gt; — font optimization still does not work

&lt;ul&gt;
&lt;li&gt;preview: &lt;a href="https://example-nextjs-webfont-optimization-50yetu6pr-ekafyi.vercel.app/"&gt;https://example-nextjs-webfont-optimization-50yetu6pr-ekafyi.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;commit &lt;a href="https://github.com/ekafyi/example-nextjs-webfont-optimization/commit/946b9806cdc3664006fabb3f2c2c8d03fbc96ecd"&gt;946b980&lt;/a&gt; - font optimization works again

&lt;ul&gt;
&lt;li&gt;preview: &lt;a href="https://example-nextjs-webfont-optimization-n2kn8qwwb-ekafyi.vercel.app/"&gt;https://example-nextjs-webfont-optimization-n2kn8qwwb-ekafyi.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; I did not find a solution and this was a deal breaker to me, so I opted out of automatic font optimization by adding this option in &lt;code&gt;next.config.js&lt;/code&gt; and roll my own font optimization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;optimizeFonts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I like the premise of this feature—improve performance by optimizing Google fonts out of the box—but &lt;em&gt;to me&lt;/em&gt; it is still too unstable to adopt for now.&lt;/p&gt;

&lt;p&gt;Also worth noting that it's fairly simple to implement web font optimization ourself using these techniques.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://csswizardry.com/2020/05/the-fastest-google-fonts"&gt;https://csswizardry.com/2020/05/the-fastest-google-fonts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.dev/optimize-webfont-loading/"&gt;https://web.dev/optimize-webfont-loading/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ahmadawais.com/google-fonts-load-faster/"&gt;https://ahmadawais.com/google-fonts-load-faster/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/masakudamatsu/loading-google-fonts-and-any-other-web-fonts-as-fast-as-possible-in-early-2021-4f5o"&gt;https://dev.to/masakudamatsu/loading-google-fonts-and-any-other-web-fonts-as-fast-as-possible-in-early-2021-4f5o&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What’s (ahem) &lt;em&gt;next&lt;/em&gt;?
&lt;/h3&gt;

&lt;p&gt;Discussions on future plans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[RFC] Automatic Font Fallback for layoutshiftless font-display: swap &lt;a href="https://github.com/vercel/next.js/discussions/24438"&gt;https://github.com/vercel/next.js/discussions/24438&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add preconnect to Automatic Webfont Optimization &lt;a href="https://github.com/vercel/next.js/discussions/24645"&gt;https://github.com/vercel/next.js/discussions/24645&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>performance</category>
    </item>
    <item>
      <title>Serverless GraphQL Server: Deploying to Netlify Functions, 3 ways</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Fri, 09 Apr 2021 17:20:39 +0000</pubDate>
      <link>https://dev.to/ekafyi/serverless-graphql-server-deploying-to-netlify-functions-3-ways-jfb</link>
      <guid>https://dev.to/ekafyi/serverless-graphql-server-deploying-to-netlify-functions-3-ways-jfb</guid>
      <description>&lt;p&gt;As a detour from my attempt at learning GraphQL resolvers and data sources, I'm going to try... &lt;em&gt;deploying a server without data sources&lt;/em&gt;. 😬&lt;/p&gt;

&lt;p&gt;There are multiple options for hosting our server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apollo Server &lt;a href="https://www.apollographql.com/docs/apollo-server/deployment" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; has sections on deploying to Heroku, Lambda, Netlify, and Azure Functions. Firebase Cloud Functions is in the same category. All of them (at the time of writing) have free tiers.&lt;/li&gt;
&lt;li&gt;For demos or starter templates, web IDEs with Node server like &lt;a href="https://codesandbox.io/" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt; and &lt;a href="https://glitch.com/" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt; can get you started quickly with &lt;em&gt;near-zero configuration&lt;/em&gt;. These are not ideal for production use if you are on a free account, since the server goes to sleep after x minutes of inactivity.&lt;/li&gt;
&lt;li&gt;Finally, you can always self-host your server if you have the resources and knowledge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post focuses on the first option, which is a good choice for those who have no/little experience deploying servers but want a robust, scalable solution.&lt;/p&gt;

&lt;p&gt;I'm going to discuss 3 ways to deploy our server on Netlify Functions. They are essentially similar and achieve the same objective, but with slight variations suited for different needs.&lt;/p&gt;

&lt;p&gt;If you've never used or (?)heard of Netlify Functions at all, here is a post I wrote last year about serverless and Netlify Functions in general.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ekafyi" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F70827%2F319e1725-cd9c-40c5-bbad-6e9be00879be.png" alt="ekafyi"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/ekafyi/getting-started-with-netlify-functions-part-1-zero-config-setup-and-writing-our-first-functions-1i5b" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Getting started with Netlify Functions — Zero-config setup and our first functions&lt;/h2&gt;
      &lt;h3&gt;Eka ・ Jul 25 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#serverless&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#jamstack&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;





&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic code and dependencies&lt;/li&gt;
&lt;li&gt;Option 1: No build&lt;/li&gt;
&lt;li&gt;Option 2: With build&lt;/li&gt;
&lt;li&gt;Option 3: With TypeScript&lt;/li&gt;
&lt;li&gt;Connecting Git repo to Netlify&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;TL;DR?&lt;/em&gt; Check out the sample repo at the end of this post.&lt;/p&gt;




&lt;h2&gt;
  
  
  Basic code and dependencies
&lt;/h2&gt;

&lt;p&gt;Let's start with our basic project setup.&lt;/p&gt;

&lt;h4&gt;
  
  
  package.json
&lt;/h4&gt;

&lt;p&gt;Like any JS app, we need a &lt;code&gt;package.json&lt;/code&gt; file for our project information, commands, and dependencies. We'll get to the commands later—now let's look at the dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dependencies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apollo-server-lambda&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^2.22.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^15.5.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;devDependencies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;encoding&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^0.1.13&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;netlify-cli&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^3.13.7&lt;/span&gt;&lt;span class="dl"&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;


&lt;ul&gt;
&lt;li&gt;Dependencies:

&lt;ul&gt;
&lt;li&gt;apollo-server-lambda

&lt;ul&gt;
&lt;li&gt;We use &lt;code&gt;apollo-server-lambda&lt;/code&gt; instead of &lt;code&gt;apollo-server&lt;/code&gt; above. &lt;a href="https://www.npmjs.com/package/apollo-server-lambda" rel="noopener noreferrer"&gt;apollo-server-lambda&lt;/a&gt; is Apollo Server's AWS Lambda integration, and Netlify Functions uses AWS Lambda under the hood.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;graphql &lt;em&gt;(...but of course)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dev dependencies:

&lt;ul&gt;
&lt;li&gt;encoding&lt;/li&gt;
&lt;li&gt;netlify-cli&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our server app does not directly use the dev dependencies, but rather they enable Netlify to build the code. At the time of writing, without these, we'll get a build error &lt;code&gt;bash: yarn: command not found&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  graphql.js
&lt;/h4&gt;

&lt;p&gt;Here is our &lt;strong&gt;server code&lt;/strong&gt;. It has to be named &lt;code&gt;graphql.js&lt;/code&gt;. To keep things simple, we use the example from Apollo documentation.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apollo-server-lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  type Query {
    hello: String
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;playground&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// enable GraphQL Playground IDE on prod env&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Don't forget to add this!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  netlify.toml
&lt;/h4&gt;

&lt;p&gt;Next, we need a &lt;strong&gt;Netlify build configuration&lt;/strong&gt; file called &lt;code&gt;netlify.toml&lt;/code&gt;. Leave the values blank for now.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;command = ""&lt;/span&gt;
  &lt;span class="s"&gt;functions = ""&lt;/span&gt;
  &lt;span class="s"&gt;publish = ""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can optionally add more options and/or configure additional environments, but these are the least we should have. &lt;/p&gt;

&lt;p&gt;These options are also available from the Netlify web UI settings. In case of conflicting values between the configuration file and the Netlify UI settings, the config file wins.&lt;/p&gt;
&lt;h2&gt;
  
  
  Option 1: No build
&lt;/h2&gt;

&lt;p&gt;This is the most simple setup we could possibly have.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /
├── functions/
│   └── graphql.js
├── static/
│   └── index.js &lt;span class="c"&gt;# can be empty but has to exist&lt;/span&gt;
├── netlify.toml
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;netlify.toml:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;command = "yarn"&lt;/span&gt;
  &lt;span class="s"&gt;functions = "functions"&lt;/span&gt;
  &lt;span class="s"&gt;publish = "static"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Our &lt;code&gt;package.json&lt;/code&gt; file is identical to the basic example above.&lt;/p&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The only command that we run on build is &lt;code&gt;yarn&lt;/code&gt;, ie. install the dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;functions = "functions"&lt;/code&gt; means our function code exists in a directory called &lt;code&gt;functions&lt;/code&gt;. You can use any name, eg. &lt;code&gt;functions = "my-functions"&lt;/code&gt;, just make sure the function code exists there.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;publish = "static"&lt;/code&gt; means our static build files are in a directory called &lt;code&gt;static&lt;/code&gt;. We only use the serverless functions here and we are not serving any web page, but this directory is required. Add an empty &lt;code&gt;index.js&lt;/code&gt; file there. Again, you can replace this with any directory name.&lt;/li&gt;
&lt;li&gt;We simply serve our code; it is not compiled. So we have to use CommonJS syntax like regular Node.js apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple and straightforward. Ideal for simple servers.&lt;/li&gt;
&lt;li&gt;Faster build time. The free plan gives us 300 build minutes per month, so faster buid time means saving money.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;del&gt;Limited capability, eg. can't use ES6 imports or anything that requires compiling/transpiling.&lt;/del&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt; Netlify recently &lt;a href="https://www.netlify.com/blog/2021/04/02/modern-faster-netlify-functions/" rel="noopener noreferrer"&gt;announced an upcoming new bundler&lt;/a&gt; that—among other features—supports using ES modules syntax. If you just want to use &lt;code&gt;import&lt;/code&gt;, optional chaining, etc, you most likely won't need &lt;code&gt;netlify-lambda build&lt;/code&gt;. It is opt-in now and will be launched as public default next May. Unfortunately I don't have time to play with it now... let me know if you have tried it! 😁&lt;/p&gt;
&lt;h2&gt;
  
  
  Option 2: With build
&lt;/h2&gt;

&lt;p&gt;First, rename the directory containing our server file (&lt;code&gt;graphql.js&lt;/code&gt;) from &lt;code&gt;functions&lt;/code&gt; to &lt;code&gt;src&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /
├── src/ &lt;span class="c"&gt;# rename from functions to src&lt;/span&gt;
│   └── graphql.js
├── static/
│   └── index.js
├── netlify.toml
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then change the command in &lt;code&gt;netlify.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;[build]
&lt;span class="gd"&gt;- command = "yarn"
&lt;/span&gt;&lt;span class="gi"&gt;+ command = "yarn build"
&lt;/span&gt;  functions = "functions"
  publish = "static"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We &lt;em&gt;don't&lt;/em&gt; change the functions directory here, the build/destination directory is still &lt;code&gt;functions&lt;/code&gt;, while our server source code now lives in &lt;code&gt;src&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We are using &lt;a href="https://github.com/netlify/netlify-lambda" rel="noopener noreferrer"&gt;netlify-lambda&lt;/a&gt; for the build step. Install it and add these commands to &lt;code&gt;package.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; netlify-lambda
&lt;span class="c"&gt;# or&lt;/span&gt;
yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; netlify-lambda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;{
  "scripts": {
&lt;span class="gi"&gt;+   "start": "netlify-lambda serve src",
+   "build": "netlify-lambda build src"
&lt;/span&gt;  },
  "devDependencies": {
    "encoding": "^0.1.13",
    "netlify-cli": "^3.13.7",
&lt;span class="gi"&gt;+   "netlify-lambda": "^2.0.3"
&lt;/span&gt;  },
  // ... no change to rest of file
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We add two commands, &lt;code&gt;serve&lt;/code&gt; (optional; you may use &lt;a href="https://www.netlify.com/products/dev/" rel="noopener noreferrer"&gt;Netlify Dev&lt;/a&gt; instead) and &lt;code&gt;build&lt;/code&gt;. In both commands, we tell netlify-lambda to build from the &lt;code&gt;src&lt;/code&gt; directory—where our function code is.&lt;/li&gt;
&lt;li&gt;netlify-lambda knows where the source files are, but how does it know &lt;em&gt;where&lt;/em&gt; to build the code a.k.a. the destination folder? It reads our &lt;code&gt;netlify.toml&lt;/code&gt; file! 🎩&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, modify our server code to use ES6 &lt;code&gt;import&lt;/code&gt; instead of the Node/CommonJS &lt;code&gt;require&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// src/graphql.js
&lt;span class="gd"&gt;- const { ApolloServer, gql } = require('apollo-server-lambda');
&lt;/span&gt;&lt;span class="gi"&gt;+ import { ApolloServer, gql } from "apollo-server-lambda";
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can have more complex Lambda functions with transpiled modern features, imports, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As a general rule, more dependencies = longer build and higher possibility of errors or incompatibilities. Only use the build step if necessary.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Option 3: With TypeScript
&lt;/h2&gt;

&lt;p&gt;We can use TypeScript with Netlify functions to take advantage of its type-checking and Intellisense features.&lt;/p&gt;

&lt;p&gt;First, install the dependencies.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @babel/preset-typescript typescript @types/node @types/aws-lambda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then create a Babel config file and a TypeScript config file in our root directory.&lt;/p&gt;

&lt;p&gt;.babelrc&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;presets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/preset-typescript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/preset-env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;targets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugins&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/plugin-proposal-class-properties&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/plugin-transform-object-assign&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/plugin-proposal-object-rest-spread&lt;/span&gt;&lt;span class="dl"&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;


&lt;p&gt;tsconfig.json&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compilerOptions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;target&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;es5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;commonjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moduleResolution&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;outDir&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./functions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strict&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;exclude&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node_modules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;functions&lt;/span&gt;&lt;span class="dl"&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;


&lt;p&gt;Your tsconfig file does not have to look like this. Just make sure the &lt;code&gt;outDir&lt;/code&gt; value matches the &lt;code&gt;functions&lt;/code&gt; value in our &lt;code&gt;netlify.toml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Rename our server file from &lt;code&gt;graphql.js&lt;/code&gt; to &lt;code&gt;graphql.ts&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This part is optional: I add a resolver function with a custom function using TS syntax. Our &lt;code&gt;hello&lt;/code&gt; query now takes an optional argument &lt;code&gt;name&lt;/code&gt;, which the server will &lt;em&gt;SHOUT!!!!&lt;/em&gt; back to us.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import { ApolloServer, gql } from "apollo-server-lambda";
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ const shout = (msg: string) =&amp;gt; {
+   return `${msg.toUpperCase()}!!!!`
+ }
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const typeDefs = gql`
&lt;/span&gt;  type Query {
&lt;span class="gi"&gt;+   hello(name: String): String
&lt;/span&gt;  }
`;
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const resolvers = {
&lt;/span&gt;  Query: {
&lt;span class="gi"&gt;+   hello: (_parent, args) =&amp;gt; shout(`Hello ${args.name || 'serverless server'}`),
&lt;/span&gt;  },
};
&lt;span class="err"&gt;
&lt;/span&gt;// ... no change to the rest of code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same as Option 2, plus TypeScript &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same as Option 2&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Connecting Git repo to Netlify
&lt;/h2&gt;

&lt;p&gt;Sign up for a free Netlify account if you haven't got one. Push your code to a Git repository (Github, Gitlab, or Bitbucket).&lt;/p&gt;

&lt;p&gt;Go to Netlify Dashboard on &lt;a href="https://app.netlify.com" rel="noopener noreferrer"&gt;https://app.netlify.com&lt;/a&gt; and choose &lt;em&gt;"New site from Git"&lt;/em&gt;. &lt;em&gt;Continuous Deployment&lt;/em&gt; is enabled by default, so Netlify deploys your site every time you push to your repo.&lt;/p&gt;

&lt;p&gt;Once deployed, you can check the build process in the &lt;em&gt;Deploys&lt;/em&gt; section on &lt;code&gt;https://app.netlify.com/sites/YOUR-SITE-NAME/deploys&lt;/code&gt;. If your build fails (😿), the logs are available there. &lt;/p&gt;

&lt;p&gt;When the build completes successfully, your serverless server function will appear in the &lt;em&gt;Functions&lt;/em&gt; section under the name &lt;code&gt;graphql&lt;/code&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%2Fuploads%2Farticles%2F22so5au35tg602pgzf0b.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%2F22so5au35tg602pgzf0b.png" alt="Netlify dashboard - functions section"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click to view its details and endpoint URL. If we enabled &lt;code&gt;playground&lt;/code&gt; config in our server code above, we can interact with our server directly by accessing GraphQL IDE from the endpoint URL.&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%2Fgrms5hz3e250hmefjupa.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%2Fgrms5hz3e250hmefjupa.png" alt="Netlify dashboard - function log"&gt;&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%2Fuploads%2Farticles%2Fytaajjj41mvor619m8mw.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%2Fytaajjj41mvor619m8mw.png" alt="GraphQL IDE playground"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can do various customizations (turn off automatic deploys, customize repo branch and base directory, and more) from &lt;em&gt;Site settings &amp;gt; Build &amp;amp; deploy&lt;/em&gt; on &lt;code&gt;https://app.netlify.com/sites/YOUR-SITE-NAME/settings/deploys&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Serverless cloud functions services like Netlify Functions enable us to get an API server live and running with no charge (to begin with), with little infrastructure and devOps knowledge.&lt;/p&gt;

&lt;p&gt;You can find all the code above in this repo. Fork it and build something fun!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ekafyi" rel="noopener noreferrer"&gt;
        ekafyi
      &lt;/a&gt; / &lt;a href="https://github.com/ekafyi/hello-graphql-server" rel="noopener noreferrer"&gt;
        hello-graphql-server
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Serverless GraphQL Server on Netlify Functions, 3 Ways&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Sample repo for &lt;a href="https://dev.to/ekafyi/serverless-graphql-server-deploying-to-netlify-functions-3-ways-jfb" rel="nofollow"&gt;my DEV.to post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Does what it says on the tin...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;no-build&lt;/code&gt; — graphql server function without build step&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;with-build&lt;/code&gt; — graphql server function with netlify-lambda build&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;with-ts&lt;/code&gt; — graphql server function with netlify-lambda build + TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Start&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/ekafyi/hello-graphql-server" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ef0cc1d083b2d67eb72500031401d9b52c3ecb9fb4c4405f46afd0d0aba02d6/68747470733a2f2f7777772e6e65746c6966792e636f6d2f696d672f6465706c6f792f627574746f6e2e737667" alt="Deploy with Netlify"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If deploying from this repo, make sure you &lt;em&gt;set the base directory&lt;/em&gt; to the directory you want to use (eg. &lt;code&gt;no-build&lt;/code&gt;). See: &lt;a href="https://docs.netlify.com/configure-builds/get-started/#definitions" rel="nofollow noopener noreferrer"&gt;https://docs.netlify.com/configure-builds/get-started/#definitions&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Else&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Or you can clone this repo and start a Git repo manually/locally from the directory you want to use.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/ekafyi/hello-graphql-server.git

&lt;span class="pl-c1"&gt;cd&lt;/span&gt; hello-graphql-server/no-build

npm install

git init&lt;/pre&gt;

&lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ekafyi/hello-graphql-server" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Thank you for reading, and stay tuned for more beginner GraphQL learning attempts. 🤞🏽&lt;/p&gt;




&lt;p&gt;References&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/netlify/netlify-lambda" rel="noopener noreferrer"&gt;https://github.com/netlify/netlify-lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/site-deploys/overview/" rel="noopener noreferrer"&gt;https://docs.netlify.com/site-deploys/overview/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/configure-builds/file-based-configuration" rel="noopener noreferrer"&gt;https://docs.netlify.com/configure-builds/file-based-configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>graphql</category>
      <category>netlifyfunctions</category>
      <category>apollo</category>
    </item>
    <item>
      <title>Power up your (API) mocking game with casual</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Sat, 27 Mar 2021 07:12:01 +0000</pubDate>
      <link>https://dev.to/ekafyi/power-up-your-api-mocking-game-with-casual-5f96</link>
      <guid>https://dev.to/ekafyi/power-up-your-api-mocking-game-with-casual-5f96</guid>
      <description>Cover image: Calvin &amp;amp; Hobbes © Bill Watterson




&lt;p&gt;Previously in this series, I made a &lt;a href="https://dev.to/ekafyi/typing-and-mocking-a-graphql-api-server-with-apollo-3f4h"&gt;GraphQL API server that returns mock data&lt;/a&gt; for a (nonexistent) app that displays my favourite music releases.&lt;/p&gt;

&lt;p&gt;Having mock data facilitates our API server's integration with other parts of design and development work, such as UI development, prototyping, and testing, even while the server's resolvers are still under development.&lt;/p&gt;

&lt;p&gt;An example query and mock data from the previous post:&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%2F1asiae42aqmuj0cyh0zd.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%2F1asiae42aqmuj0cyh0zd.png" alt="GraphQL IDE showing query and JSON data of tracks and albums"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, this mock data could do with some improvements, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;track_number&lt;/code&gt; field—indicating a song/track’s order in an album—could return a negative integer (impossible) or a very large one (how many albums do you know contains 91 tracks??).&lt;/li&gt;
&lt;li&gt;All albums, tracks, and artists have the same mock names, &lt;em&gt;"Album/Track Title"&lt;/em&gt; and &lt;em&gt;Artist Name&lt;/em&gt;. We want to develop and test the UI with varying data, including artists with a &lt;a href="https://open.spotify.com/artist/6wBUn8gMP85n8dPu6LoUcF" rel="noopener noreferrer"&gt;very long name&lt;/a&gt; or songs with a &lt;a href="https://open.spotify.com/track/56QCsnXzOlh3oSdPhrOjhO" rel="noopener noreferrer"&gt;very long title&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are going to use a library called &lt;a href="https://www.npmjs.com/package/casual" rel="noopener noreferrer"&gt;casual&lt;/a&gt; for our custom mock data.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/boo1ean" rel="noopener noreferrer"&gt;
        boo1ean
      &lt;/a&gt; / &lt;a href="https://github.com/boo1ean/casual" rel="noopener noreferrer"&gt;
        casual
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Fake data generator for javascript
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Fake data generator &lt;a href="https://travis-ci.org/boo1ean/casual" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9493f0620f7b77510e1a17b4a9cff10bd015cdc384823b13f954d0aaec24667a/68747470733a2f2f7472617669732d63692e6f72672f626f6f3165616e2f63617375616c2e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;LOOKING FOR CONTRIBUTORS&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a class="issue-link js-issue-link" href="https://github.com/boo1ean/casual/issues/109" rel="noopener noreferrer"&gt;#109&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;npm install casual&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;casual&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'casual'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// Generate random sentence&lt;/span&gt;
&lt;span class="pl-c"&gt;// You don't need function call operator here&lt;/span&gt;
&lt;span class="pl-c"&gt;// because most of generators use properties mechanism&lt;/span&gt;
&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;sentence&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;casual&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;sentence&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// Generate random city name&lt;/span&gt;
&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;city&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;casual&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;city&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// Define custom generator&lt;/span&gt;
&lt;span class="pl-s1"&gt;casual&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;define&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'point'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-k"&gt;function&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-c1"&gt;x&lt;/span&gt;: &lt;span class="pl-v"&gt;Math&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;random&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
        &lt;span class="pl-c1"&gt;y&lt;/span&gt;: &lt;span class="pl-v"&gt;Math&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;random&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// Generate random point&lt;/span&gt;
&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;point&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;casual&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;point&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// And so on..&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Casual uses javascript properties for common generators so you don't need to use function call operator&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Embedded generators&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;// Address&lt;/span&gt;
&lt;span class="pl-s1"&gt;casual&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;country&lt;/span&gt;              &lt;span class="pl-c"&gt;// 'United Kingdom'&lt;/span&gt;
&lt;span class="pl-s1"&gt;casual&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;city&lt;/span&gt;                 &lt;span class="pl-c"&gt;// 'New Ortiz chester'&lt;/span&gt;
&lt;span class="pl-s1"&gt;casual&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;zip&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;digits&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/boo1ean/casual" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Installation&lt;/li&gt;
&lt;li&gt;Basic usage&lt;/li&gt;
&lt;li&gt;More basic usage examples&lt;/li&gt;
&lt;li&gt;Custom generators with casual.define&lt;/li&gt;
&lt;li&gt;Custom providers with casual.register_provider&lt;/li&gt;
&lt;li&gt;Localization&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;casual &lt;span class="c"&gt;# or yarn add casual&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Import/require casual in your server app main script (eg. &lt;code&gt;index.js&lt;/code&gt; or &lt;code&gt;app.js&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;casual&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Basic usage
&lt;/h2&gt;

&lt;p&gt;Casual comes with dozens of built-in generators (in the form of properties and functions) that return dummy data for various common purposes such as user data, addresses, numbers, dates, copy text, etc.&lt;/p&gt;

&lt;p&gt;In an Apollo GraphQL server, we pass a casual generator to our &lt;a href="https://www.apollographql.com/docs/apollo-server/testing/mocking/#customizing-mocks" rel="noopener noreferrer"&gt;custom mocks object&lt;/a&gt; so it returns the value generated by casual.&lt;/p&gt;

&lt;p&gt;My mocks object now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Artist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Artist Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ...etc&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's replace the dummy text &lt;em&gt;"Artist Name"&lt;/em&gt; with &lt;code&gt;casual.name&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;const mocks = {
&lt;/span&gt;  Artist: () =&amp;gt; {
&lt;span class="gd"&gt;-   return { name: () =&amp;gt; "Artist Name" };
&lt;/span&gt;&lt;span class="gi"&gt;+   return { name: () =&amp;gt; casual.name };
&lt;/span&gt;  },
  // ...etc
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server now returns mock artist names such as...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Ms. Timothy Lesch"
"Mrs. Napoleon Hayes"
"Dr. Alisha Cole"
"Mr. Celia Lockman"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unusual artist names for sure 😁, but at least they are not all &lt;em&gt;"Artist Name&lt;/em&gt; anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. More basic examples
&lt;/h2&gt;

&lt;p&gt;Now let’s try other simple built-in generators.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;const mocks = {
&lt;/span&gt;  Artist: () =&amp;gt; {
    return { name: () =&amp;gt; casual.name };
  },
  Album: () =&amp;gt; {
    return {
      // ... other fields
&lt;span class="gi"&gt;+     release_date: () =&amp;gt; casual.date()
&lt;/span&gt;    };
  },
  Track: () =&amp;gt; {
    return {
      // ... other fields
&lt;span class="gi"&gt;+     track_number: () =&amp;gt; casual.integer(1, 12)
&lt;/span&gt;    };
  },
&lt;span class="gi"&gt;+ ExternalUrlObject: () =&amp;gt; {
+   return { spotify: () =&amp;gt; casual.url };
+ },
&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;casual.date()&lt;/code&gt; is a function that returns a date string, eg. &lt;code&gt;"2021-03-25"&lt;/code&gt;. It takes an optional argument, a &lt;a href="http://momentjs.com/docs/#/parsing/string-format/" rel="noopener noreferrer"&gt;momentjs-compatible formatter&lt;/a&gt;. If no argument is passed, it uses the default format &lt;code&gt;'YYYY-MM-DD'&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;casual.integer(1,12)&lt;/code&gt; is a function that returns an integer between &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;12&lt;/code&gt;, thus solving our track number predicament. (Yes, we could roll our own random integer generator without a library, but this is helpful in terms of speed.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;casual.url&lt;/code&gt; is a property that returns an URL, eg. &lt;code&gt;'http://www.Germaine.net/'&lt;/code&gt;. For some reason, the domain name is always capitalized, so I add &lt;code&gt;.toLowerCase()&lt;/code&gt; in my full code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Combining generators
&lt;/h4&gt;

&lt;p&gt;We can also combine generator functions. For instance: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;casual.words(5)&lt;/code&gt; returns five random words&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;casual.integer(1,6)&lt;/code&gt; returns a random integer between &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;6&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can use &lt;code&gt;casual.words(casual.integer(1, 6))&lt;/code&gt; to return &lt;em&gt;a phrase that consists of one to six words&lt;/em&gt;. This gives us a (slightly) better control of the text length compared to generators like &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;text&lt;/code&gt;, and &lt;code&gt;description&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Custom generators with casual.define
&lt;/h2&gt;

&lt;p&gt;We can define custom generators with &lt;code&gt;casual.define(name, fn)&lt;/code&gt;. The first argument is the generator name and the second is a function returning the value.&lt;/p&gt;

&lt;p&gt;Let's make a custom &lt;code&gt;artist_name&lt;/code&gt; generator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;artist_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// TODO return something&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want the mock artist name to return either &lt;em&gt;a person’s name&lt;/em&gt; (representing solo artists) or &lt;em&gt;a group/band name&lt;/em&gt;. I’ve got a list of fictional band names from &lt;a href="https://www.indiesound.com/band-name-generator/" rel="noopener noreferrer"&gt;Band Name Generator&lt;/a&gt; for the latter, and for the person names I'm simply using the &lt;code&gt;casual.full_name&lt;/code&gt; generator.&lt;/p&gt;

&lt;p&gt;I define the band names in a hardcoded array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bandNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Crystal Greener&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The Threshold Renewable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unevenly Optimist&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// ... etc&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next I’m going to: (1) pick one name out of the &lt;code&gt;bandNames&lt;/code&gt; array, and (2) randomize returning either a person name or a band name. The &lt;code&gt;casual.random_element()&lt;/code&gt; helper, which returns an item from the array passed as argument, is perfect for those.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;artist_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// pass array containing a person full_name and a band name to return at random&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random_element&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;full_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bandNames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// get a random band name&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;Then we use it in our mock resolver function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;Artist: () =&amp;gt; {
&lt;/span&gt;&lt;span class="gi"&gt;+  return { name: () =&amp;gt; casual.artist_name };
&lt;/span&gt;},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we run our query, now we get a list of more realistic artist names. 🎉&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Price Tillman"
"The Out Garter"
"Colby Bergnaum"
"The Threshold Renewable"
"Raphael Kohler"
"The Fountains Altars"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can go beyond an individual field (eg. name) and define an object type in the same way, for example define a &lt;code&gt;casual.artist&lt;/code&gt; generator that returns an object with &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;bio&lt;/code&gt; properties. Make sure the object shape matches the type definition, though.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;artist&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;artist_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;bio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&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;h2&gt;
  
  
  5. Custom providers with casual.register_provider
&lt;/h2&gt;

&lt;p&gt;Under the hood, casual generators are simply functions in a &lt;strong&gt;provider object&lt;/strong&gt;. Casual includes the following &lt;a href="https://github.com/boo1ean/casual/tree/master/src/providers" rel="noopener noreferrer"&gt;built-in providers&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;address&lt;/li&gt;
&lt;li&gt;color&lt;/li&gt;
&lt;li&gt;date&lt;/li&gt;
&lt;li&gt;internet&lt;/li&gt;
&lt;li&gt;payment&lt;/li&gt;
&lt;li&gt;person&lt;/li&gt;
&lt;li&gt;misc&lt;/li&gt;
&lt;li&gt;number&lt;/li&gt;
&lt;li&gt;text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;full_name&lt;/code&gt; generator, for example, is defined in the &lt;code&gt;person&lt;/code&gt; provider (&lt;a href="https://github.com/boo1ean/casual/blob/master/src/providers/person.js#L49-L51" rel="noopener noreferrer"&gt;source code&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;casual.define&lt;/code&gt; is sufficient for one-off individual generators, but if we have an object type with multiple fields/properties to mock up, we can &lt;strong&gt;register our own custom providers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, a music track would not only have a name/title but also track number, tempo in BPM (beats per minute), and duration in millisecond. Let's try registering a custom &lt;code&gt;music_provider&lt;/code&gt;. First we create an object and pass it to   &lt;code&gt;casual.register_provider()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;music_provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// TODO add functions or properties here&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;music_provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we add the generator functions as the object properties. For example, we're adding &lt;code&gt;track_number&lt;/code&gt; and &lt;code&gt;tempo&lt;/code&gt; to our music provider.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;music_provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Track number in an album, between 1 to 12&lt;/span&gt;
  &lt;span class="na"&gt;track_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

  &lt;span class="c1"&gt;// Song tempo in BPM, between 60 to 180&lt;/span&gt;
  &lt;span class="na"&gt;tempo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;music_provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since these are regular functions, we can define our generator to accept arguments. For example, we can make an &lt;code&gt;artist_name&lt;/code&gt; generator that accepts a &lt;code&gt;type&lt;/code&gt; argument of &lt;code&gt;"PERSON"&lt;/code&gt; or &lt;code&gt;"GROUP"&lt;/code&gt;. If no argument is provided, we return any of those at random.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bandNames&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="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// same data as Step 4&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;music_provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... other generators&lt;/span&gt;

  &lt;span class="c1"&gt;// Return an artist name. Name can be a solo artist's name ("PERSON") or a band name ("GROUP").&lt;/span&gt;
  &lt;span class="na"&gt;artist_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PERSON&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;full_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GROUP&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bandNames&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random_element&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;full_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bandNames&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;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The best way to see what we can do when defining providers is to look at the source code, eg. &lt;a href="https://github.com/boo1ean/casual/blob/master/src/providers/address.js" rel="noopener noreferrer"&gt;the address provider&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use the generators from our custom provider, we call them the same way as built-in or custom defined ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Artist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;artist_name&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;Track&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;track_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;track_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;tempo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;casual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tempo&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Localization
&lt;/h2&gt;

&lt;p&gt;Casual comes with localization built-in. Simply add the locale name when calling the default import. For example, to get the Indonesian locale:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- const casual = require('casual');
&lt;/span&gt;&lt;span class="gi"&gt;+ const casual = require('casual').id_ID;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Locale providers are simply copies of the default providers in directories with the locale names (&lt;code&gt;en_US&lt;/code&gt;, &lt;code&gt;fr_FR&lt;/code&gt;, &lt;code&gt;id_ID&lt;/code&gt;, etc) — &lt;a href="https://github.com/boo1ean/casual/tree/master/src/providers" rel="noopener noreferrer"&gt;see source&lt;/a&gt;. These locale providers are submitted by contributors.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;digression&amp;gt;&lt;/code&gt;&lt;br&gt;
Off topic but interesting (to me): While looking at the locale providers, I learned that &lt;a href="https://github.com/boo1ean/casual/blob/master/src/providers/ru_RU/person.js#L134-L136" rel="noopener noreferrer"&gt;Russian female last names&lt;/a&gt; are the male last names + an &lt;code&gt;a&lt;/code&gt; in the end. I went on to Google the tennis athlete &lt;em&gt;Anna Kournikova&lt;/em&gt; and sure enough, her father's name is &lt;em&gt;Kournikov&lt;/em&gt;.&lt;br&gt;
&lt;code&gt;&amp;lt;/digression&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When a localized provider is not available, it falls back to the default (English). For instance, the &lt;a href="https://github.com/boo1ean/casual/tree/master/src/providers/id_ID" rel="noopener noreferrer"&gt;Indonesian locale&lt;/a&gt; only has the &lt;code&gt;address&lt;/code&gt; provider, so everything else uses the default.&lt;/p&gt;

&lt;p&gt;We barely scratched the surface with casual. Check out &lt;a href="https://github.com/boo1ean/casual#readme" rel="noopener noreferrer"&gt;their docs&lt;/a&gt; to see all available functionalities.&lt;/p&gt;




&lt;p&gt;Enough mocking for now—in the next post I'm going to start learning about GraphQL server resolvers. Thank you for reading!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>casual</category>
      <category>api</category>
    </item>
    <item>
      <title>Typing and mocking a GraphQL API server with Apollo</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Fri, 26 Mar 2021 03:52:01 +0000</pubDate>
      <link>https://dev.to/ekafyi/typing-and-mocking-a-graphql-api-server-with-apollo-3f4h</link>
      <guid>https://dev.to/ekafyi/typing-and-mocking-a-graphql-api-server-with-apollo-3f4h</guid>
      <description>&lt;p&gt;Previously in this series, I made a &lt;a href="https://pbrg9.sse.codesandbox.io/" rel="noopener noreferrer"&gt;GraphQL server that returns nothing&lt;/a&gt;. Now I'm going to design the schema (&lt;strong&gt;type&lt;/strong&gt; defintions) and set up &lt;strong&gt;mocking&lt;/strong&gt; functionality. Since I have yet to build the resolvers (which retrieve data from a database or other sources), the server will now return &lt;em&gt;mock data&lt;/em&gt; based on the schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;I'm building the API for a hypothetical app that displays my favourite music releases. The API server shall return &lt;strong&gt;a list of music releases&lt;/strong&gt;; each list item shall have a title, an artwork image, artist name(s), and URL to play on Spotify.&lt;/p&gt;

&lt;p&gt;I borrowed the basic models and descriptions from &lt;a href="https://developer.spotify.com/documentation/web-api/reference/#objects-index" rel="noopener noreferrer"&gt;Spotify Web API official documentation&lt;/a&gt; via an &lt;a href="https://dev.to/ekafyi/converting-spotify-web-api-objects-to-graphql-schema-object-type-definitions-h04"&gt;app that converts Spotify API’s objects into GraphQL schema&lt;/a&gt; I’d built earlier, liberally simplified and modified for this purpose.&lt;/p&gt;

&lt;p&gt;TL;DR? View (and fork) the &lt;a href="https://codesandbox.io/s/mock-music-releases-server-kqt0s" rel="noopener noreferrer"&gt;live CodeSandbox app&lt;/a&gt; ↓&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/kqt0s"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Typing
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;schema&lt;/strong&gt; describes our GraphQL API’s data models, relations, and operations. It is comprised of &lt;strong&gt;type definitions&lt;/strong&gt; written in a syntax called the &lt;strong&gt;Schema Definition Language&lt;/strong&gt; (also called the "GraphQL schema").&lt;/p&gt;

&lt;p&gt;So... what exactly are these &lt;strong&gt;types&lt;/strong&gt; that we define? GraphQL recognizes a number of type categories.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entry-point types: &lt;code&gt;Query&lt;/code&gt; and &lt;code&gt;Mutation&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Object types&lt;/li&gt;
&lt;li&gt;(Default/built-in) Scalar types&lt;/li&gt;
&lt;li&gt;Custom scalar types&lt;/li&gt;
&lt;li&gt;Enum types&lt;/li&gt;
&lt;li&gt;Input types&lt;/li&gt;
&lt;li&gt;Abstract types: unions and interfaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are only using some of those now, but I'm including references at the end of the post if you’d like to learn more.&lt;/p&gt;

&lt;p&gt;Quick copypasta of types we're going to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="c"&gt;# Query type&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Object types&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Artist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Album&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Track&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Enum type&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AlbumType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Interface type and object type that implements it&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Album&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Union type (we're discussing but _not_ using this)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Album&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Track&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Object types
&lt;/h3&gt;

&lt;p&gt;An object type represents &lt;em&gt;a kind of object&lt;/em&gt; (...who would’ve thought? 😬) containing &lt;em&gt;a collection of fields&lt;/em&gt; (properties) that can be fetched from some data source(s). A GraphQL schema is usually largely comprised of these types.&lt;/p&gt;

&lt;p&gt;For our schema, let’s define the object types &lt;code&gt;Artist&lt;/code&gt;, &lt;code&gt;Album&lt;/code&gt;, &lt;code&gt;Track&lt;/code&gt;, and &lt;code&gt;Image&lt;/code&gt; (truncated for brevity).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Artist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;!]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Album&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;artists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Artist&lt;/span&gt;&lt;span class="p"&gt;!]!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;!]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;release_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Track&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;artists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Artist&lt;/span&gt;&lt;span class="p"&gt;!]!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;album&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Album&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;track_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;preview_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;An object type must contain at least one field. The object type &lt;code&gt;Artist&lt;/code&gt; contains fields called &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;images&lt;/code&gt; (and so on).&lt;/li&gt;
&lt;li&gt;The field type can be...

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;scalar type&lt;/strong&gt; (&lt;code&gt;ID&lt;/code&gt;, &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Int&lt;/code&gt;—details below),&lt;/li&gt;
&lt;li&gt;or another &lt;strong&gt;object type&lt;/strong&gt; (eg. in the &lt;code&gt;Track&lt;/code&gt; object type, the &lt;code&gt;album&lt;/code&gt; field contains an &lt;code&gt;Album&lt;/code&gt; object). &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The exclamation mark &lt;code&gt;!&lt;/code&gt; indicates a &lt;strong&gt;required field&lt;/strong&gt;; lack of which indicates nullable.&lt;/li&gt;

&lt;li&gt;The square brackets &lt;code&gt;[]&lt;/code&gt; indicates a &lt;strong&gt;list/array&lt;/strong&gt; of the type inside the brackets.

&lt;ul&gt;
&lt;li&gt;eg. &lt;code&gt;[String]&lt;/code&gt; = a list of strings, &lt;code&gt;[Artist]&lt;/code&gt; = a list of &lt;code&gt;Artist&lt;/code&gt; objects.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;artists: [Artist!]!&lt;/code&gt; means the &lt;code&gt;artists&lt;/code&gt; field is required and cannot be null (right-side/outer exclamation mark). It cannot return an empty array, either; it must contain at least one &lt;code&gt;Artist&lt;/code&gt; object (inner exclamation mark).&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Note that the SDL is agnostic with regards to data sources; we don’t have to define object types and fields in relation to any database table/column structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query type
&lt;/h3&gt;

&lt;p&gt;This is &lt;em&gt;the only required part&lt;/em&gt; of a schema. Technically, it’s possible to have &lt;a href="https://dev.to/ekafyi/serving-nothing-through-graphql-58cc"&gt;a server without a single object type&lt;/a&gt;. But we will get an error if the &lt;code&gt;Query&lt;/code&gt; type does not exist.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Query&lt;/code&gt; and &lt;code&gt;Mutation&lt;/code&gt; are GraphQL’s special &lt;em&gt;top-level, entry point&lt;/em&gt; types. Clients, ie. front-end apps, can only retrieve (read) data through &lt;code&gt;Query&lt;/code&gt; and store/update/delete (write) data through &lt;code&gt;Mutation&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Unlike a REST API, a GraphQL API has no multiple endpoints. Clients don't send a GET request to &lt;code&gt;/albums&lt;/code&gt; for a list of albums and another to &lt;code&gt;/artists/:id&lt;/code&gt; for the artist data; they simply &lt;em&gt;send a single query&lt;/em&gt; with a list of fields they need, which are the fields in our &lt;code&gt;Query&lt;/code&gt; type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;type Query {
&lt;/span&gt;&lt;span class="gi"&gt;+  albums: [Album!]
+  tracks: [Track!]
&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our schema above, clients can query for &lt;code&gt;albums&lt;/code&gt;, which will include the relevant artists and images data (if they include those fields in the request). Likewise for &lt;code&gt;tracks&lt;/code&gt;. &lt;em&gt;But&lt;/em&gt; they cannot get a list of artists or images, since our type definition does not include such fields.&lt;/p&gt;

&lt;p&gt;Like object types and &lt;code&gt;Mutation&lt;/code&gt;, &lt;code&gt;Query&lt;/code&gt; fields can accept arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;type Query {
&lt;/span&gt;  albums: [Album!]
  tracks: [Track!]
&lt;span class="gi"&gt;+ album(id: ID!): Album
+ track(id: ID!): Track
&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last two fields enable clients to query a single album or a single track by passing an &lt;code&gt;id&lt;/code&gt; as argument.&lt;/p&gt;

&lt;p&gt;Note: We are not discussing &lt;code&gt;Mutation&lt;/code&gt; here, but it's essentially &lt;code&gt;Query&lt;/code&gt;'s counterpart for POST/PUT/DELETE operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scalar types
&lt;/h3&gt;

&lt;p&gt;Some fields above have types like &lt;code&gt;Int&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt;—these are the default/built-in &lt;strong&gt;scalar types&lt;/strong&gt;, which are GraphQL schema’s &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Primitive" rel="noopener noreferrer"&gt;primitive types&lt;/a&gt; equivalent. There are five scalar types: &lt;code&gt;ID&lt;/code&gt;, &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Int&lt;/code&gt;, &lt;code&gt;Float&lt;/code&gt;, &lt;code&gt;Boolean&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We can also define our own &lt;a href="https://www.apollographql.com/docs/apollo-server/schema/custom-scalars/" rel="noopener noreferrer"&gt;custom scalar types&lt;/a&gt;. Apollo Server provides the &lt;code&gt;GraphQLScalarType&lt;/code&gt; constructor class to facilitate defining our custom scalar logic, which we then pass to a custom resolver. I'm going to discuss this part in a separate post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enum types
&lt;/h3&gt;

&lt;p&gt;Like other typed languages, GraphQL SDL has an &lt;a href="https://en.wikipedia.org/wiki/Enumerated_type" rel="noopener noreferrer"&gt;enumerated type&lt;/a&gt;, a.k.a. &lt;strong&gt;enum&lt;/strong&gt;. An enum field type can only have one of the predefined string values.&lt;/p&gt;

&lt;p&gt;The Spotify API’s &lt;a href="https://developer.spotify.com/documentation/web-api/reference/#object-albumobject" rel="noopener noreferrer"&gt;AlbumObject&lt;/a&gt; has an &lt;code&gt;album_type&lt;/code&gt; field, originally typed &lt;code&gt;String&lt;/code&gt;, whose value is one of &lt;em&gt;"album"&lt;/em&gt;, &lt;em&gt;"single"&lt;/em&gt;, or &lt;em&gt;"compilation"&lt;/em&gt;. Let’s define it as an enum type in our schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;type Album {
&lt;/span&gt;  id: ID!
  name: String!
  artists: [Artist!]!
  images: [Image!]
  release_date: String
&lt;span class="gi"&gt;+ album_type: AlbumType
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ enum AlbumType {
+   ALBUM
+   SINGLE
+   COMPILATION
+ }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to type safety (when querying and displaying on the frontend, when passing as query argument, as well as when making mutations), using enum types also gives us the benefit of intellisense/autocompletion in supported IDEs.&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%2Finoy6h2re009k2cdtuec.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%2Finoy6h2re009k2cdtuec.png" alt="IDE showing available AlbumType values"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that the enum values have to be in UPPERCASE as per GraphQL specs. If the values in the data source (eg. database) are in lowercase, we can map them in a &lt;em&gt;custom resolver function&lt;/em&gt;. Not only for mapping cases of course, we can use it eg. to map colour shorthands into corresponding hex values, as shown in &lt;a href="https://www.apollographql.com/docs/apollo-server/schema/schema/#internal-values-advanced" rel="noopener noreferrer"&gt;the Apollo Server documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Union and interface types
&lt;/h3&gt;

&lt;p&gt;The last types we're going to discuss are the abstract types. Essentially, they represent &lt;em&gt;a type that could be any of multiple object types&lt;/em&gt;. Quick definitions by &lt;a href="https://graphql-ruby.org/type_definitions" rel="noopener noreferrer"&gt;GraphQL Ruby&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interface:&lt;/strong&gt; "a list of fields which may be implemented by object types"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Union:&lt;/strong&gt; "a set of object types which may appear in the same spot"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(🤔 ...huh?)&lt;/p&gt;

&lt;p&gt;We're going to see how &lt;em&gt;either one&lt;/em&gt; could be used in our schema to describe "a music release, which could either be an album or a track".&lt;/p&gt;

&lt;h4&gt;
  
  
  Option A — with union
&lt;/h4&gt;

&lt;p&gt;One possible approach is by defining &lt;strong&gt;a union type&lt;/strong&gt; called &lt;code&gt;Release&lt;/code&gt;, which could either be an &lt;code&gt;Album&lt;/code&gt; or a &lt;code&gt;Track&lt;/code&gt; object type. Then we add a field called &lt;code&gt;releases&lt;/code&gt; to the query, which returns a list of &lt;code&gt;Release&lt;/code&gt; objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+ union Release = Album | Track
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;type Query {
&lt;/span&gt;  albums: [Album!]
  tracks: [Track!]
&lt;span class="gi"&gt;+ releases: [Release!]
&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Album&lt;/code&gt; and &lt;code&gt;Track&lt;/code&gt; definitions stay the same.&lt;/li&gt;
&lt;li&gt;A union can only consist of two or more &lt;em&gt;object types&lt;/em&gt;, not scalar or any other types. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unexpectedly (to me), this type is &lt;em&gt;not&lt;/em&gt; intended for mixed scalar and object types, eg. a field that could be an integer or a particular object type. We need &lt;em&gt;custom scalars&lt;/em&gt; for that instead. Related discussions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/graphql/graphql-js/pull/242" rel="noopener noreferrer"&gt;https://github.com/graphql/graphql-js/pull/242&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/graphql/graphql-spec/issues/215" rel="noopener noreferrer"&gt;https://github.com/graphql/graphql-spec/issues/215&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Option B — with interface
&lt;/h4&gt;

&lt;p&gt;Alternatively, we can define &lt;strong&gt;an interface type&lt;/strong&gt; called &lt;code&gt;Release&lt;/code&gt;, which is then &lt;em&gt;implemented&lt;/em&gt; by the &lt;code&gt;Album&lt;/code&gt; and &lt;code&gt;Track&lt;/code&gt; object types. It contains the fields &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;artists&lt;/code&gt;, which both &lt;code&gt;Album&lt;/code&gt; and &lt;code&gt;Track&lt;/code&gt; have. Like in option A, we add a field called &lt;code&gt;releases&lt;/code&gt; to the query, which returns a list of &lt;code&gt;Release&lt;/code&gt; objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+ interface Release {
+   id: ID!
+   name: String!
+   artists: [Artist!]!
+ }
&lt;/span&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="gd"&gt;- type Album {
&lt;/span&gt;&lt;span class="gi"&gt;+ type Album implements Release {
&lt;/span&gt;  id: ID!
  name: String!
  artists: [Artist!]!
  images: [Image!]
  release_date: String
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;- type Track {
&lt;/span&gt;&lt;span class="gi"&gt;+ type Track implements Release {
&lt;/span&gt;  id: ID!
  name: String!
  artists: [Artist!]!
  album: Album!
  track_number: Int
  preview_url: String
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;type Query {
&lt;/span&gt;  albums: [Album!]
  tracks: [Track!]
&lt;span class="gi"&gt;+ releases: [Release!]
&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another unexpected-to-me finding: We still have to include the common interface fields in the object type fields (in this case &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;artists&lt;/code&gt;). Yes, we write &lt;code&gt;id: ID!&lt;/code&gt; three times and they have to be identical.&lt;/p&gt;

&lt;h4&gt;
  
  
  So... are they interchangeable?
&lt;/h4&gt;

&lt;p&gt;I ended up in a rabbit hole researching these two types’ difference in usage, but it &lt;em&gt;is&lt;/em&gt; an interesting topic! I will probably revisit this in a separate post.&lt;/p&gt;

&lt;p&gt;TL;DR + IMO: They are &lt;em&gt;conceptually different, but share similar characteristics&lt;/em&gt; as abstract types, which enable them to solve the same problems (such as our &lt;code&gt;Release&lt;/code&gt; type) albeit in different ways.&lt;/p&gt;

&lt;p&gt;On a more practical level, when querying, we use &lt;a href="https://graphql.org/learn/queries/#inline-fragments" rel="noopener noreferrer"&gt;inline fragments&lt;/a&gt; differently with union and interface types.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;union type&lt;/strong&gt; does not know what fields each object type does/does not have. So we have to specify &lt;em&gt;all fields inside the inline fragments&lt;/em&gt;, including the identical ones (eg. &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;artists&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GetUnionReleases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;latest_releases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Album&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c"&gt;# name and artists fields here...&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;artists&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Track&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c"&gt;# ...name and artists fields again here&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;artists&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;album&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meanwhile, with an &lt;strong&gt;interface type&lt;/strong&gt; we can specify the common fields (the interface’s fields) outside the fragments. The &lt;code&gt;Release&lt;/code&gt; interface &lt;em&gt;always&lt;/em&gt; contains &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;artists&lt;/code&gt; fields, so we can query them outside the inline fragments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GetInterfaceReleases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;latest_releases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c"&gt;# interface’s fields&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;artists&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c"&gt;# object type specific fields in the fragments&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Album&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Track&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;album&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These queries will be made from the clients that consume our API, but you can try it from the server app’s GraphQL Playground IDE. For this app, I decided to use the &lt;strong&gt;interface type&lt;/strong&gt; to define &lt;code&gt;Release&lt;/code&gt; (option B).&lt;/p&gt;

&lt;h2&gt;
  
  
  Half-time
&lt;/h2&gt;

&lt;p&gt;Let’s see our code so far.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apollo-server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  type Query {
    albums: [Album!]
    tracks: [Track!]
    releases: [Release!]
  }
  # ... the rest of the schema
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`🚀 Server ready at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;



&lt;p&gt;The server is up and running, and the GraphQL Playground IDE shows the documentation and autocomplete feature based on our type definitions.&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%2Fqs1wj6vbvbxghkasseg7.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%2Fqs1wj6vbvbxghkasseg7.png" alt="GraphQL Playground IDE showing releases query with autocomplete fields and list of available objects on the right pane"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also use &lt;a href="https://www.apollographql.com/docs/studio/" rel="noopener noreferrer"&gt;Apollo Studio&lt;/a&gt; to access—among other things—a more powerful and dev-friendly query builder.&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%2Fkg76gvghh1zewu1mmy7f.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%2Fkg76gvghh1zewu1mmy7f.png" alt="Apollo Studio query builder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above we can see the &lt;code&gt;Release&lt;/code&gt; interface detail, including the types that implement it. When I select the &lt;code&gt;images&lt;/code&gt; field under &lt;code&gt;Album&lt;/code&gt;, it automatically builds the inline fragment in the query. Smooth! 😎&lt;/p&gt;

&lt;p&gt;But when we &lt;em&gt;run&lt;/em&gt; the query, the server returns &lt;code&gt;null&lt;/code&gt; because we have not set up the resolvers, which will return each field value. Fortunately, Apollo Server has an extensive mocking feature based on our type definitions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Mocking
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mocks out of the box
&lt;/h3&gt;

&lt;p&gt;Add a &lt;code&gt;mocks: true&lt;/code&gt; option when creating a server instance to enable the &lt;strong&gt;default mock resolvers&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;When we send the query... the returned data is no longer &lt;code&gt;null&lt;/code&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%2Fuploads%2Farticles%2Ffugviidso5jp5ldfr8hh.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%2Ffugviidso5jp5ldfr8hh.png" alt="GraphQL IDE showing mock data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's query some more data...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;releases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;artists&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Album&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;album_type&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;release_date&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Track&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;track_number&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;explicit&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and here is the returned mock data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"releases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"f4570e2d-9221-4a8e-ae5d-6cf0bcb3c10e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"artists"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"track_number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"explicit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"be550404-7bad-46c7-a314-cb88ceec1710"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"artists"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"album_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"COMPILATION"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"release_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ID&lt;/code&gt; is mocked as random string uuid. Nice!&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;String&lt;/code&gt; is mocked as &lt;code&gt;Hello world&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Int&lt;/code&gt; is randomly generated.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Boolean&lt;/code&gt; and enum types are correctly typed!&lt;/li&gt;
&lt;li&gt;Array types always return 1-2 items (depending on the number of fields).&lt;/li&gt;
&lt;li&gt;We don't have custom scalar type here. If we did, we would have to pass a custom resolver for the mock to work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is pretty cool, considering it takes literally five seconds to implement. But let's make the mock data resemble our expected data better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom mock resolvers
&lt;/h3&gt;

&lt;p&gt;Pass an object to the &lt;code&gt;mocks&lt;/code&gt; option to enable &lt;strong&gt;custom mock resolvers&lt;/strong&gt;. As the name suggests, they are identically shaped to the actual resolvers, both of which correspond to the schema. Each property is a &lt;em&gt;function&lt;/em&gt; that returns the corresponding mock value.&lt;/p&gt;

&lt;p&gt;For example, this replaces &lt;em&gt;"Hello world"&lt;/em&gt; with &lt;em&gt;"My custom mock string"&lt;/em&gt; for the &lt;code&gt;String&lt;/code&gt; scalar type value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- const mocks = true;
&lt;/span&gt;&lt;span class="gi"&gt;+ const mocks = {
+   String: () =&amp;gt; "My custom mock string"
+ };
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const server = new ApolloServer({
&lt;/span&gt;   typeDefs,
&lt;span class="gi"&gt;+  mocks,
&lt;/span&gt;});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the album, track, and artist names are all &lt;code&gt;String&lt;/code&gt;. Does not make much sense if they all return &lt;em&gt;"My custom mock string"&lt;/em&gt;, does it?&lt;/p&gt;

&lt;p&gt;Luckily, we can mock our object types the same way. Remove the &lt;code&gt;String&lt;/code&gt; function and add &lt;code&gt;Album&lt;/code&gt;, &lt;code&gt;Track&lt;/code&gt;, and &lt;code&gt;Artist&lt;/code&gt; functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;const mocks = {
&lt;/span&gt;&lt;span class="gd"&gt;-   String: () =&amp;gt; "My custom mock string"
&lt;/span&gt;&lt;span class="gi"&gt;+   Album: () =&amp;gt; {
+     return { name: () =&amp;gt; "Album Title" };
+   },
+   Track: () =&amp;gt; {
+     return { name: () =&amp;gt; "Track Title" };
+   },
+   Artist: () =&amp;gt; {
+     return { name: () =&amp;gt; "Artist Name" };
+   }
&lt;/span&gt;};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's send another query and see the returned mock data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;releases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;__typename&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;artists&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Album&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;album_type&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Track&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;track_number&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"releases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"__typename"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Track"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Track Title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"artists"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Artist Name"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Artist Name"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"track_number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"__typename"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Album"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Album Title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"artists"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Artist Name"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Artist Name"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"album_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALBUM"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that although we only pass the &lt;code&gt;name&lt;/code&gt; function, the mock logic uses the default mock logic for the remaining fields (eg. &lt;code&gt;track_number&lt;/code&gt; in &lt;code&gt;Track&lt;/code&gt;, &lt;code&gt;album_type&lt;/code&gt; in &lt;code&gt;Album&lt;/code&gt;). Nice!&lt;/p&gt;

&lt;h3&gt;
  
  
  MockList
&lt;/h3&gt;

&lt;p&gt;Lists—such as &lt;code&gt;releases&lt;/code&gt; and &lt;code&gt;artists&lt;/code&gt;—return two items by default. What if we need different number of items mocked? Apollo Server provides the &lt;code&gt;MockList&lt;/code&gt; constructor to customize the number of items in a list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;const { 
&lt;/span&gt;   ApolloServer,
&lt;span class="gi"&gt;+  MockList 
&lt;/span&gt;} = require("apollo-server");
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const mocks = {
&lt;/span&gt;  Album: () =&amp;gt; {
&lt;span class="gd"&gt;-   return { name: () =&amp;gt; "Album Title" };
&lt;/span&gt;&lt;span class="gi"&gt;+   return { name: () =&amp;gt; "Album Title", artists: () =&amp;gt; new MockList(1) };
&lt;/span&gt;  },
&lt;span class="err"&gt;
&lt;/span&gt;  Track: () =&amp;gt; {
&lt;span class="gd"&gt;-   return { name: () =&amp;gt; "Track Title" };
&lt;/span&gt;&lt;span class="gi"&gt;+   return { name: () =&amp;gt; "Track Title", artists: () =&amp;gt; new MockList(1) };
&lt;/span&gt;  },
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ Query: () =&amp;gt; {
+   return { releases: () =&amp;gt; new MockList([0, 15]) };
+ }
&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Although an album or track can have more than one artists (eg. featuring/collaboration), most albums and tracks just have one artist. Let's add an &lt;code&gt;artists&lt;/code&gt; mock resolver to &lt;code&gt;Album&lt;/code&gt; and &lt;code&gt;Track&lt;/code&gt; which returns a &lt;code&gt;MockList&lt;/code&gt; object. The integer argument &lt;code&gt;1&lt;/code&gt; means always return one item.&lt;/li&gt;
&lt;li&gt;Meanwhile in &lt;code&gt;Query&lt;/code&gt;, we add &lt;code&gt;releases&lt;/code&gt; that return between 0 to 15 items, using the array argument &lt;code&gt;[0, 15]&lt;/code&gt;. This is particularly useful for testing and UI development/prototyping—what an empty state looks like, what the pagination looks like, what an "awkward" number of item (eg. just 1) looks like.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now when we run our query, the returned mock data looks like this.&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%2Fa7pnplf4ivpbr5h94vu2.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%2Fa7pnplf4ivpbr5h94vu2.png" alt="GraphQL IDE showing more than 2 releases"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's still not ideal (&lt;code&gt;track_number: -60&lt;/code&gt; anyone? 😬), but we've got some mock data to test and start developing the UI/frontend app with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together
&lt;/h2&gt;

&lt;p&gt;In this post, we define our API’s types and their relations (&lt;code&gt;Query&lt;/code&gt;, object types, enums, interface) in the GraphQL schema language and pass it as template literal to Apollo Server’s &lt;code&gt;gql&lt;/code&gt; parser. Then we use the built-in &lt;code&gt;mocks&lt;/code&gt; option so our server returns mock data based on our type definitions. We use custom mock resolvers to customize our mock data behaviour.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next post in this series, where I'm going to improve my mocks with &lt;code&gt;casual&lt;/code&gt; fake data generator!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://graphql.org/learn/" rel="noopener noreferrer"&gt;GraphQL.org - Introduction to GraphQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official documentation: 

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/apollo-server/" rel="noopener noreferrer"&gt;Introduction to Apollo Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/apollo-server/schema/schema/" rel="noopener noreferrer"&gt;Schema and types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/apollo-server/testing/mocking/" rel="noopener noreferrer"&gt;Mocking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/apollo-server/api/apollo-server/" rel="noopener noreferrer"&gt;API reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="http://odyssey.apollographql.com/" rel="noopener noreferrer"&gt;Apollo Odyssey Fullstack Tutorial&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://www.howtographql.com/" rel="noopener noreferrer"&gt;How to GraphQL Fullstack Tutorial&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>graphql</category>
      <category>apolloserver</category>
    </item>
    <item>
      <title>Serving nothing through GraphQL</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Sat, 20 Mar 2021 16:45:23 +0000</pubDate>
      <link>https://dev.to/ekafyi/serving-nothing-through-graphql-58cc</link>
      <guid>https://dev.to/ekafyi/serving-nothing-through-graphql-58cc</guid>
      <description>&lt;p&gt;&lt;em&gt;The absolute minimal GraphQL server (with a hint of existential crisis)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I was taking Apollo’s beginner-level &lt;a href="https://odyssey.apollographql.com"&gt;Odyssey interactive tutorials&lt;/a&gt;, having been trying and failing to learn GraphQL on and off over the last year. Midway through, I started wondering what &lt;em&gt;the most simple GraphQL server setup&lt;/em&gt; looks like, so I made a server that returns &lt;em&gt;nothing&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This is obviously not meant to be a pragmatic example. If you want to see basic Apollo Server examples with sensible defaults instead, go to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://codesandbox.io/s/apollo-server-apollo-server"&gt;Apollo Server CodeSandbox template&lt;/a&gt; — fork it to get a live GraphQL server in 5 seconds&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/apollographql/odyssey-lift-off-part1/tree/complete"&gt;https://github.com/apollographql/odyssey-lift-off-part1/tree/complete&lt;/a&gt; — the Apollo Odyssey course companion app&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/apollo-server/getting-started/"&gt;Official documentation “Getting Started” tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What do we need?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Any Node.js app. I build mine locally on my machine from scratch, but you can use IDEs like Glitch or Codesandbox or use an existing project.&lt;/li&gt;
&lt;li&gt;If building locally, &lt;code&gt;node&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt; should be installed.&lt;/li&gt;
&lt;li&gt;How I made my app: 

&lt;ul&gt;
&lt;li&gt;Create the app directory and go there&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm init&lt;/code&gt;, go with all default values&lt;/li&gt;
&lt;li&gt;(Optional) Install nodemon to monitor our app and auto-reload when the code changes:  &lt;code&gt;npm i --save-dev nodemon&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;package.json&lt;/code&gt;, add &lt;code&gt;"start": "nodemon index.js localhost 4000"&lt;/code&gt; to the &lt;code&gt;scripts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Create our main script file, eg. &lt;code&gt;index.js&lt;/code&gt;. This is where we're going to write our server code. It can be called anything, eg. &lt;code&gt;app.js&lt;/code&gt;. Make sure it matches the command in &lt;code&gt;package.json&lt;/code&gt;. 

&lt;ul&gt;
&lt;li&gt;If using a template or adding to an existing app, open your &lt;code&gt;package.json&lt;/code&gt; and see what the main script is called.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are ready to set up the GraphQL server!&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install dependencies and import functions&lt;/li&gt;
&lt;li&gt;Create our type definitions schema&lt;/li&gt;
&lt;li&gt;Create a new ApolloServer object&lt;/li&gt;
&lt;li&gt;Start the server&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Install dependencies and import functions
&lt;/h3&gt;

&lt;p&gt;We need two packages as dependencies: &lt;code&gt;graphql&lt;/code&gt; and &lt;code&gt;apollo-server&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run in your app root directory&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;apollo-server graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then import &lt;code&gt;ApolloServer&lt;/code&gt; and &lt;code&gt;gql&lt;/code&gt; from &lt;code&gt;apollo-server&lt;/code&gt; in our script file, eg. &lt;code&gt;index.js&lt;/code&gt;. We're going to use them in the next steps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apollo-server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Create our type definitions schema
&lt;/h3&gt;

&lt;p&gt;Next we create our &lt;strong&gt;type definitions&lt;/strong&gt;, which describe the shape of the data our server will resolve and return. We write our definition as a string literal in a syntax called the GraphQL Schema Definition Language, then pass it to the template literal tag &lt;code&gt;gql&lt;/code&gt; we imported in Step 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  # TODO add type definitions here
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are multiple different of types, but here we simply define the &lt;code&gt;Query&lt;/code&gt; type, where clients can query for &lt;code&gt;nothings&lt;/code&gt;. This field shall return an array of string (it doesn't matter as I'm not planning to return anything—but it has to be defined), and it is nullable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  type Query {
    nothings: [String]
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://graphql.org/learn/schema/"&gt;https://graphql.org/learn/schema/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/apollo-server/schema/schema/"&gt;https://www.apollographql.com/docs/apollo-server/schema/schema/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/apollo-server/api/apollo-server/#gql"&gt;https://www.apollographql.com/docs/apollo-server/api/apollo-server/#gql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Create our server object
&lt;/h3&gt;

&lt;p&gt;Now we instantiate the &lt;code&gt;ApolloServer&lt;/code&gt; constructor class—ie. we create a new ApolloServer object—that takes an option object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// TODO add options here&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this test app, we are passing one option from Step 2, &lt;code&gt;typeDefs&lt;/code&gt;. You can see the complete list of options in the link below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// shorthand for `typeDefs: typeDefs`&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/apollo-server/api/apollo-server/#options"&gt;https://www.apollographql.com/docs/apollo-server/api/apollo-server/#options&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Start the server
&lt;/h3&gt;

&lt;p&gt;Finally, we add the command to start our server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`🚀 Server ready at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;



&lt;p&gt;Run &lt;code&gt;npm run start&lt;/code&gt; to start our first GraphQL server. You will see something like this on your CLI console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[nodemon] starting `node index.js localhost 4000`
🚀 Server ready at http://localhost:4000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While our server is running, we can access the &lt;a href="https://www.apollographql.com/docs/apollo-server/testing/graphql-playground/"&gt;GraphQL Playground&lt;/a&gt; on the server URL itself, in this case &lt;code&gt;localhost:4000&lt;/code&gt;. It provides a quick, convenient graphical interface to interact with our server.&lt;/p&gt;

&lt;p&gt;Write an opening &lt;code&gt;{&lt;/code&gt; and press spacebar to open list of available fields. Here we only have one field, &lt;code&gt;nothings&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yZJMq8QR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d99hfu53bj74nuq1blvl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yZJMq8QR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d99hfu53bj74nuq1blvl.png" alt="GraphQL Playground IDE showing a query input area with pop-up menu containing list of fields"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we have our query for &lt;code&gt;nothings&lt;/code&gt;, press the "Run" icon, and our server returns the data (or lack thereof, in this case).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8WL34DUU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pnq07782iqgvt6vnqcz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8WL34DUU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pnq07782iqgvt6vnqcz1.png" alt="GraphQL Playground IDE showing a query for nothings on the left column and the result of null on the right column"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it, we've got a server that serves nothing! 😁 Below is the full server code.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/nothing-apollo-server-pbrg9?module=/index.js"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Learn more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/apollo-server/api/apollo-server/#listen"&gt;https://www.apollographql.com/docs/apollo-server/api/apollo-server/#listen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/graphql/graphql-playground"&gt;https://github.com/graphql/graphql-playground&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Random remarks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Where are the resolvers?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's interesting that while we &lt;em&gt;have to&lt;/em&gt; provide type definitions (the server won't run if we pass an empty option object or don't pass any argument), technically we don’t even need to pass resolvers in order to have a running GraphQL server 😮. (We do need to write resolvers to make a server that returns data, of course.)&lt;/p&gt;

&lt;p&gt;Explanation: &lt;code&gt;resolvers&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; required, but Apollo Server provides default resolvers if none is explicitly provided. When running at the top level as in our code here, it cannot look for anything from the parent and returns &lt;code&gt;null&lt;/code&gt;—but that explains why we don't get an error despite not passing any resolver. See the logic: &lt;a href="https://www.apollographql.com/docs/apollo-server/data/resolvers/#default-resolvers"&gt;https://www.apollographql.com/docs/apollo-server/data/resolvers/#default-resolvers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phew, it’s regular JavaScript&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As someone who primarily works with frontend development and never built an API server before, to be honest I didn't know what it entailed—what languages and tools are necessary? This sample server demonstrates that it only requires intermediate-level vanilla JavaScript plus SDL for the type definitions. (I presume data retrieving and storing, deploying, CI/CD (etc) require knowledge of other languages and tools, but not for setting up the server itself.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I sure as heck don’t want to get stuck with a server that returns nothing 😆. Going to explore these next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mocks&lt;/li&gt;
&lt;li&gt;Resolvers and data sources&lt;/li&gt;
&lt;li&gt;Deploying&lt;/li&gt;
&lt;li&gt;?? ...and more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See you in the next posts!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>apolloserver</category>
    </item>
    <item>
      <title>Converting Spotify Web API Objects to GraphQL Schema Object Type Definitions</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Sun, 14 Mar 2021 09:34:34 +0000</pubDate>
      <link>https://dev.to/ekafyi/converting-spotify-web-api-objects-to-graphql-schema-object-type-definitions-h04</link>
      <guid>https://dev.to/ekafyi/converting-spotify-web-api-objects-to-graphql-schema-object-type-definitions-h04</guid>
      <description>&lt;p&gt;I made a &lt;a href="https://wsywh.sse.codesandbox.io"&gt;web application&lt;/a&gt; that scrapes and displays the &lt;a href="https://developer.spotify.com/documentation/web-api/reference/#objects-index"&gt;Spotify Web API&lt;/a&gt; objects in two formats: GraphQL Schema Definition Language (SDL) and JSON.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/spotify-web-object-types-wsywh"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;SimplifiedTrackObject&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spotify official documentation &lt;a href="https://developer.spotify.com/documentation/web-api/reference/#object-simplifiedtrackobject"&gt;https://developer.spotify.com/documentation/web-api/reference/#object-simplifiedtrackobject&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GraphQL schema format  &lt;a href="https://wsywh.sse.codesandbox.io/SimplifiedTrackObject/schema"&gt;https://wsywh.sse.codesandbox.io/SimplifiedTrackObject/schema&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;JSON format &lt;a href="https://wsywh.sse.codesandbox.io/SimplifiedTrackObject/json"&gt;https://wsywh.sse.codesandbox.io/SimplifiedTrackObject/json&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The stack:&lt;/strong&gt; 🥞&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js app with the &lt;a href="https://expressjs.com"&gt;Express&lt;/a&gt; framework&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mozilla.github.io/nunjucks/"&gt;Nunjucks&lt;/a&gt; templating engine for the index view&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cheerio.js.org/"&gt;Cheerio&lt;/a&gt; for parsing data from HTML&lt;/li&gt;
&lt;li&gt;Hosted on &lt;a href="http://codesandbox.io/"&gt;CodeSandbox&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why did I make this app?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  As part of learning about the GraphQL schema
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Schema&lt;/strong&gt; is a key concept in GraphQL. It specifies what kinds of data clients can request and what operations clients can perform through a GraphQL API. It consists &lt;strong&gt;of type definitions&lt;/strong&gt;, written in a syntax called the &lt;strong&gt;Schema Definition Language&lt;/strong&gt; (SDL). In many implementations, we pass the type definitions to template literal tags such as &lt;a href="https://www.apollographql.com/docs/apollo-server/api/apollo-server/#gql"&gt;gql&lt;/a&gt; in Apollo Server and &lt;a href="https://www.gatsbyjs.com/docs/reference/config-files/actions/#createTypes"&gt;createTypes&lt;/a&gt; in Gatsby.&lt;/p&gt;

&lt;p&gt;Example from &lt;a href="https://www.apollographql.com/docs/apollo-server/api/apollo-server/#gql"&gt;Apollo Server documentation&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  type Author {
    name
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example from &lt;a href="https://www.gatsbyjs.com/docs/reference/graphql-data-layer/schema-customization/#fixing-field-types"&gt;Gatsby documentation&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createSchemaCustomization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    type AuthorJson implements Node {
      joinedAt: Date
    }
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createTypes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;typeDefs&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;Took me a while 😬, but I just realised that since &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals"&gt;template literals&lt;/a&gt; are strings, a schema type definition is actually, &lt;em&gt;literally&lt;/em&gt; (pun intended), a regular &lt;em&gt;string&lt;/em&gt;. It is then processed by functions such as &lt;code&gt;gql&lt;/code&gt; and &lt;code&gt;createTypes&lt;/code&gt; above into a schema format required by respective libraries.&lt;/p&gt;

&lt;p&gt;My hypothesis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apollo-server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// We can do this...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  type Author {
    name
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...and we can also do this?? 🤔&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefsString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  type Author {
    name
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;typeDefsString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If true, this means full versatility of where and how we get the data for our schema without requiring a transpiling/compiling step. Instead of manually writing the type definitions in SDL, for instance, we may have a "single source of truth" file in any format readable by JavaScript. We can even &lt;em&gt;programmatically scrape a documentation web page&lt;/em&gt; to build the schema. &lt;/p&gt;

&lt;p&gt;And thus, I got the idea to scrape the Spotify API documentation page and transform the data into GraphQL SDL. &lt;/p&gt;

&lt;p&gt;When this app was finished, I used the resulting object type definitions in my local Apollo GraphQL server, and &lt;em&gt;it worked&lt;/em&gt;, confirming my above hypothesis on versatile schema data source.&lt;/p&gt;

&lt;h3&gt;
  
  
  To see how a large-scale production app’s data models and relations are depicted in a schema
&lt;/h3&gt;

&lt;p&gt;Documentations and beginner-level tutorials, understandably, focus on the API/concept and use highly simplified, shortened schemas. Converting Spotify API's objects to schema format gave me an idea of what I will be dealing with when setting up schema for a production app. This leads to the next point...&lt;/p&gt;

&lt;h3&gt;
  
  
  To better understand REST and GraphQL API behaviours
&lt;/h3&gt;

&lt;p&gt;Despite identical database structure, models, and relations, different API architectures require different way of thinking. Observing object types designed for a large production app on REST API and converting them to GraphQL schema highlights the different perspectives between the two.&lt;/p&gt;

&lt;p&gt;For example, the Spotify API has &lt;a href="https://developer.spotify.com/documentation/web-api/reference/#object-artistobject"&gt;ArtistObject&lt;/a&gt; and &lt;a href="https://developer.spotify.com/documentation/web-api/reference/#object-simplifiedartistobject"&gt;SimplifiedArtistObject&lt;/a&gt;. The former is used eg. when returning a single artist, and the latter when including artist data in a track or an album. The former contains fields like &lt;code&gt;followers&lt;/code&gt; and &lt;code&gt;genres&lt;/code&gt;, which are never needed in the latter use cases. This distinction is necessary for a REST API, but may not be needed for a GraphQL one. Clients simply request the fields they need from the &lt;code&gt;ArtistObject&lt;/code&gt; type.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does this app work?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Scrape the Spotify documentation page with &lt;a href="https://github.com/request/request"&gt;request&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;For the sake of speed, I copied the HTML into a local file in the node app’s public directory and read it with &lt;a href="https://nodejs.org/api/fs.html"&gt;fs&lt;/a&gt; instead.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Parse the HTML string with cheerio to find the objects data.

&lt;ul&gt;
&lt;li&gt;It doesn't matter where the data comes from (remote URL, local file), as long as we pass &lt;em&gt;HTML string&lt;/em&gt; to cheerio: &lt;code&gt;const $ = cheerio.load(scraper.scrapeLocal())&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Cheerio is based off core jQuery, so we use jQuery selectors—which for the most part resembles DOM element selectors—to find the data we need: &lt;code&gt;const unformattedObjectTypes = $("#reference-index + .left-split-container &amp;gt; .row:last-child ul li")&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Heads up: As Cheerio relies on the markup selectors to parse data, if we use a remote source (ie. Spotify documentation page) and the markup changes, our code breaks. I use a local file for this app, so this will not happen.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Now I've got a list of object types; each object type has multiple fields, each of which has a name, description, and type. Then I prepare the data to send to our routes. The data preparation process consists of two separate things:

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;first group&lt;/strong&gt; is &lt;strong&gt;minor adjustment/formatting tasks&lt;/strong&gt; such as getting the innerText of target elements, trimming whitespace, replacing double quote marks, etc. &lt;/li&gt;
&lt;li&gt;I did not have much time to work on this MVP, so I removed double quote marks and omitted description with complex markup (eg. &lt;code&gt;reason&lt;/code&gt; field in &lt;a href="https://developer.spotify.com/documentation/web-api/reference/#object-trackrestrictionobject"&gt;TrackRestrictionObject&lt;/a&gt; has lists and formatted content in the description). Note that we &lt;em&gt;can&lt;/em&gt; have multi-line description in GraphQL schema by wrapping it in three double quote marks, and we can convert HTML markup to Markdown syntax for the description.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;second group&lt;/strong&gt; is related to &lt;strong&gt;syntax and specification differences&lt;/strong&gt; between Spotify's documentation and SDL requirements. 

&lt;ul&gt;
&lt;li&gt;Minor syntax differences: &lt;code&gt;[SomeObjectType]&lt;/code&gt; instead of &lt;code&gt;Array[SomeObjectType]&lt;/code&gt;, &lt;code&gt;Int&lt;/code&gt; instead of &lt;code&gt;Integer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;SDL uses &lt;em&gt;union types&lt;/em&gt;, eg. &lt;code&gt;union TrackOrEpisode = TrackObject | EpisodeObject&lt;/code&gt; instead of directly using &lt;code&gt;TrackObject | EpisodeObject&lt;/code&gt; in the object field type.&lt;/li&gt;
&lt;li&gt;SDL cannot have an empty type. &lt;a href="https://developer.spotify.com/documentation/web-api/reference/#object-trackobject"&gt;TrackObject&lt;/a&gt; has empty &lt;code&gt;linked_from&lt;/code&gt;, which should be replaced with something else (&lt;code&gt;LinkedTrackObject&lt;/code&gt; maybe?).&lt;/li&gt;
&lt;li&gt;SDL does not recognize generic &lt;code&gt;Object&lt;/code&gt; or &lt;code&gt;any&lt;/code&gt; type. &lt;a href="https://developer.spotify.com/documentation/web-api/reference/#object-pagingobject"&gt;PagingObject&lt;/a&gt; has an &lt;code&gt;Array[Object]&lt;/code&gt; type, which could be replaced either once we know what &lt;code&gt;Object&lt;/code&gt; refers to, &lt;em&gt;or&lt;/em&gt; by making a custom generic scalar type.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;I have not fixed these, but I found these interesting to note. Of course, if I were refactoring a REST API codebase for my own/my workplace's app, I would have more information (and time!) to address them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Finally, I return the data in appropriate format for each route (schema in plain text, json, and HTML page for the home page). I use Nunjucks for the home page, which is not necessary but makes the code tidier. I also add a parameter to save the data to a static file (&lt;code&gt;object-types.txt&lt;/code&gt; and &lt;code&gt;object-types.json&lt;/code&gt;) for faster access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Caveat/notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This app simply returns the object types data as string in the SDL format. It does not fetch or serve or interact with data in any way. It demonstrates what a GraphQL type definition looks like without getting into the implementation.&lt;/li&gt;
&lt;li&gt;Related to the point above, a GraphQL schema does not only contain object type definitions but also GraphQL-specific types like &lt;code&gt;Query&lt;/code&gt;, &lt;code&gt;Mutation&lt;/code&gt;, and &lt;code&gt;Subscription&lt;/code&gt;. This app does not address those.&lt;/li&gt;
&lt;li&gt;This app is hosted on a free CodeSandbox account, so it shuts down after a few minutes of inactivity. If I were using it for a production app, I would host it on a server that is always on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I learn more about GraphQL I plan to build a GraphQL server of some sorts with schema from this app. Til then, thank you for reading and take care.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GraphQL introduction and beginner tutorials

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.howtographql.com/"&gt;https://www.howtographql.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://odyssey.apollographql.com/"&gt;https://odyssey.apollographql.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://graphql.org/learn/"&gt;https://graphql.org/learn/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;GraphQL schema and SDL

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://graphql.org/learn/schema/"&gt;https://graphql.org/learn/schema/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.howtographql.com/basics/2-core-concepts/"&gt;https://www.howtographql.com/basics/2-core-concepts/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/apollo-server/schema/schema/"&gt;https://www.apollographql.com/docs/apollo-server/schema/schema/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.prisma.io/blog/graphql-sdl-schema-definition-language-6755bcb9ce51"&gt;https://www.prisma.io/blog/graphql-sdl-schema-definition-language-6755bcb9ce51&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>graphql</category>
      <category>spotifywebapi</category>
    </item>
    <item>
      <title>Pull (fetch) from a forked GitHub repository</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Thu, 08 Oct 2020 09:22:42 +0000</pubDate>
      <link>https://dev.to/ekafyi/pull-fetch-from-a-forked-github-repository-1p9p</link>
      <guid>https://dev.to/ekafyi/pull-fetch-from-a-forked-github-repository-1p9p</guid>
      <description>&lt;p&gt;You are working on a project outside of your or your organisation account--an open source project for &lt;a href="https://dev.to/devteam/happy-hacktoberfest-here-s-how-to-show-up-for-open-source-this-month-4cee"&gt;Hacktoberfest&lt;/a&gt;, perhaps. You forked the repo and started working on it.&lt;/p&gt;

&lt;p&gt;Meanwhile, the original repo has been updated with new changes. To prevent conflict, you need to pull these changes from the &lt;em&gt;original&lt;/em&gt; repo and merge it to your local, forked branch. But wait... how do you do that? ❓🤔&lt;/p&gt;

&lt;p&gt;Follow these steps and you'll be good to go. 😎&lt;/p&gt;

&lt;p&gt;(1) add remote&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(2) fetch&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch upstream
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Commits to the remote &lt;code&gt;main&lt;/code&gt; branch will be stored in a local branch called &lt;code&gt;upstream/main&lt;/code&gt; (same with other branches).&lt;/p&gt;

&lt;p&gt;(3) merge to local, then merge to your working branch (if necessary)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main
git merge upstream/main

&lt;span class="c"&gt;# merge to working branch&lt;/span&gt;
git checkout eka/working-branch
git merge main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Done!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork"&gt;https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/syncing-a-fork"&gt;https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/syncing-a-fork&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>github</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Add Theme UI to your NextJS site</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Sat, 01 Aug 2020 16:58:32 +0000</pubDate>
      <link>https://dev.to/ekafyi/add-theme-ui-to-your-nextjs-site-1c6</link>
      <guid>https://dev.to/ekafyi/add-theme-ui-to-your-nextjs-site-1c6</guid>
      <description>&lt;p&gt;&lt;a href="https://theme-ui.com/"&gt;Theme UI&lt;/a&gt; is a React styling library “based on constraint-based design principles”, where we can centralize our design tokens in a regular JavaScript &lt;em&gt;theme object&lt;/em&gt; . Although there’s no Theme UI plugin specifically for NextJS like &lt;a href="https://theme-ui.com/getting-started/gatsby"&gt;for Gatsby&lt;/a&gt;, we can add Theme UI to our NextJS web app/site in three straightforward steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Install theme-ui&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; theme-ui
&lt;span class="c"&gt;# or yarn add theme-ui&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Create and export the theme object&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/utils/theme.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#111&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tomato&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#3f3f3f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;muted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#e0e0e0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;highlight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#9f9f9f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#6c6c6c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#3f3f3f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;fonts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Comic Sans MS&lt;/span&gt;&lt;span class="dl"&gt;"&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;



&lt;p&gt;You can use any filename and directory, just make sure you import it correctly in the next step. See more &lt;a href="https://theme-ui.com/theming"&gt;theming references&lt;/a&gt; and &lt;a href="https://theme-ui.com/demo"&gt;demo&lt;/a&gt; in the Theme UI docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Wrap our NextJS app with Theme UI’s ThemeProvider&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We achieve this by making use of NextJS’s custom &lt;code&gt;App&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/pages/_app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;NextApp&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ThemeProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme-ui&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../utils/theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// theme object from step 2&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;NextApp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ThemeProvider&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ThemeProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&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;



&lt;p&gt;We also add Theme UI’s &lt;code&gt;InitializeColorMode&lt;/code&gt; to NextJS’s custom &lt;code&gt;Document&lt;/code&gt; to prevent flash of colour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/pages/_document.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextScript&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/document&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;InitializeColorMode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme-ui&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Document&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;getInitialProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getInitialProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;initialProps&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Replace html lang attribute value with your language.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InitializeColorMode&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Main&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NextScript&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&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;



&lt;p&gt;Learn more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://theme-ui.com/api/#initializecolormode"&gt;https://theme-ui.com/api/#initializecolormode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/advanced-features/custom-app"&gt;https://nextjs.org/docs/advanced-features/custom-app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/advanced-features/custom-document"&gt;https://nextjs.org/docs/advanced-features/custom-document&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Does it work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We should be able to use the &lt;code&gt;sx&lt;/code&gt;  property in our components. Remember to use the &lt;code&gt;@jsx&lt;/code&gt; pragma and import &lt;code&gt;jsx&lt;/code&gt; in order to use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/any-component.js&lt;/span&gt;
&lt;span class="cm"&gt;/** @jsx jsx */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jsx&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme-ui&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;SomeComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;sx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;tomato&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;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;



&lt;p&gt;Run &lt;code&gt;npm run dev&lt;/code&gt; (or &lt;code&gt;yarn dev&lt;/code&gt;) to check if the theme styles have been applied.&lt;/p&gt;

&lt;p&gt;That’s it, we have added Theme UI in our NextJS site!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>themeui</category>
    </item>
    <item>
      <title>Go serverless with this JungleJS + Netlify functions starter site</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Thu, 30 Jul 2020 13:07:38 +0000</pubDate>
      <link>https://dev.to/ekafyi/go-serverless-with-this-junglejs-netlify-functions-starter-site-3bg0</link>
      <guid>https://dev.to/ekafyi/go-serverless-with-this-junglejs-netlify-functions-starter-site-3bg0</guid>
      <description>&lt;p&gt;&lt;a href="https://www.junglejs.org/" rel="noopener noreferrer"&gt;JungleJS&lt;/a&gt; is a static site generator, meaning that it generates every single route and compiles all the assets on build time. Since it’s a Svelte app, we can take advantage of &lt;a href="https://svelte.dev/tutorial/onmount" rel="noopener noreferrer"&gt;Svelte’s lifecycle&lt;/a&gt; to create interactive UI with client-side requests if necessary. For most landing pages, blog, or portfolio/profile websites, this should be enough. It’s simple, performant, and saves hosting costs. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But sometimes we need a server&lt;/strong&gt; (even when it’s not our own). A common use case for server-side operation is to send authenticated requests. Say we use the Mailchimp API to add users to our newsletter, or maybe the Spotify API to suggest a playlist based on the user’s mood.  Both require us to send a key or token to identify ourselves. We cannot do this on the client-side because everyone can open the browser dev tools, find our secret keys, and do &lt;em&gt;anything&lt;/em&gt; on behalf of our account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/RyXVu4ZW454IM/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/RyXVu4ZW454IM/giphy.gif" alt="Hackerman gif"&gt;&lt;/a&gt;&lt;/p&gt;
Does not even take a “hacker” to find our credentials if we send it from the browser.



&lt;p&gt;Here’s where serverless functions come in. In a nutshell, these are a cloud service that allow us to run a server that is hosted, configured, and managed by a third-party, such as &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;, &lt;a href="https://www.netlify.com/products/functions" rel="noopener noreferrer"&gt;Netlify Functions&lt;/a&gt;, and &lt;a href="https://firebase.google.com/products/functions" rel="noopener noreferrer"&gt;Firebase Cloud Functions&lt;/a&gt;. I just learned about Netlify functions recently, so I made this starter site that combines JungleJS with Netlify functions. &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ekafyi" rel="noopener noreferrer"&gt;
        ekafyi
      &lt;/a&gt; / &lt;a href="https://github.com/ekafyi/junglejs-netlify-functions" rel="noopener noreferrer"&gt;
        junglejs-netlify-functions
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Starter site for JungleJS + Netlify Functions + Storybook + TailwindCSS
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;JungleJS + Netlify Functions starter site&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/e34f1b5abe9e1e3def583eb56fb3ac8d3a741f68313bec4d24bcb99674f5bede/68747470733a2f2f696d6167652e666c617469636f6e2e636f6d2f69636f6e732f7376672f323935302f323935303533322e737667"&gt;&lt;img src="https://camo.githubusercontent.com/e34f1b5abe9e1e3def583eb56fb3ac8d3a741f68313bec4d24bcb99674f5bede/68747470733a2f2f696d6167652e666c617469636f6e2e636f6d2f69636f6e732f7376672f323935302f323935303533322e737667" width="80" height="80" alt=""&gt;&lt;/a&gt;  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/893cd331c98d992d6fcecb5d3403254a060005a91e4ca46d1d797c795dfd16c2/68747470733a2f2f7365656b6c6f676f2e636f6d2f696d616765732f4e2f6e65746c6966792d6c6f676f2d373538373232434446342d7365656b6c6f676f2e636f6d2e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/893cd331c98d992d6fcecb5d3403254a060005a91e4ca46d1d797c795dfd16c2/68747470733a2f2f7365656b6c6f676f2e636f6d2f696d616765732f4e2f6e65746c6966792d6c6f676f2d373538373232434446342d7365656b6c6f676f2e636f6d2e706e67" width="80" height="80" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A starter site with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.junglejs.org" rel="nofollow noopener noreferrer"&gt;JungleJS&lt;/a&gt; — Svelte and GraphQL-based static site generator&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.netlify.com/products/functions/" rel="nofollow noopener noreferrer"&gt;Netlify Functions&lt;/a&gt; — Serverless functions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://storybook.js.org" rel="nofollow noopener noreferrer"&gt;Storybook&lt;/a&gt; — UI development environment&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tailwindcss.com" rel="nofollow noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; — utility-first CSS framework&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Introductory posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/ekafyi/go-serverless-with-this-junglejs-netlify-functions-starter-site-3bg0" rel="nofollow"&gt;Go serverless with this JungleJS + Netlify functions starter site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/ekafyi/getting-started-with-netlify-functions-part-1-zero-config-setup-and-writing-our-first-functions-1i5b" rel="nofollow"&gt;Getting Started with Netlify Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick start&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://vercel.com/import/git?s=https%3A%2F%2Fgithub.com%2Fekafyi%2Fjunglejs-netlify-functions%2Ftree%2Fmaster" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/20bea215d35a4e28f2c92ea5b657d006b087687486858a40de2922a4636301ab/68747470733a2f2f76657263656c2e636f6d2f627574746f6e" alt="Deploy with Vercel"&gt;&lt;/a&gt; &lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/ekafyi/junglejs-netlify-functions" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ef0cc1d083b2d67eb72500031401d9b52c3ecb9fb4c4405f46afd0d0aba02d6/68747470733a2f2f7777772e6e65746c6966792e636f6d2f696d672f6465706c6f792f627574746f6e2e737667" alt="Deploy with Netlify"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Or &lt;a href="https://github.com/ekafyi/junglejs-netlify-functions/generate" rel="noopener noreferrer"&gt;create a new repo&lt;/a&gt; with Github template.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install and develop&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Install the global Netlify CLI package if you haven’t&lt;/span&gt;
npm install netlify-cli -g

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Clone and go to project directory&lt;/span&gt;
git clone https://github.com/ekafyi/junglejs-netlify-functions.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; junglejs-netlify-functions

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Install dependencies&lt;/span&gt;
npm install

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Start Netlify Dev server&lt;/span&gt;
netlify dev

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; (Optional) Start Storybook server in a separate tab&lt;/span&gt;
npm run storybook&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Netlify Dev serves your site on &lt;code&gt;localhost:3333&lt;/code&gt;. Your functions run on &lt;code&gt;localhost:3333/.netlify/functions/{YOUR_FUNCTION_NAME}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This starter comes with a sample function &lt;code&gt;hello.js&lt;/code&gt;, which you can access on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;localhost:3333/.netlify/functions/hello&lt;/li&gt;
&lt;li&gt;localhost:3333/.netlify/functions/hello?name=Eka (example with query parameter)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you start…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ekafyi/junglejs-netlify-functions" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This is a simple starter with a &lt;code&gt;netlify.toml&lt;/code&gt; configuration and a sample function in &lt;code&gt;functions/hello.js&lt;/code&gt;. It’s based off &lt;a href="https://github.com/ekafyi/junglejs-storybook-tailwind" rel="noopener noreferrer"&gt;my previous starter site&lt;/a&gt;, which includes Storybook and Tailwind CSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Do any of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone by running &lt;code&gt;git clone https://github.com/ekafyi/junglejs-netlify-functions.git&lt;/code&gt; on your CLI&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ekafyi/junglejs-netlify-functions/generate" rel="noopener noreferrer"&gt;Create new repo with Github template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/ekafyi/junglejs-netlify-functions" rel="noopener noreferrer"&gt;Deploy with Netlify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com/import/git?s=https%3A%2F%2Fgithub.com%2Fekafyi%2Fjunglejs-netlify-functions%2Ftree%2Fmaster" rel="noopener noreferrer"&gt;Deploy with Vercel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then run &lt;code&gt;netlify dev&lt;/code&gt; (or &lt;code&gt;ntl dev&lt;/code&gt; for short) to start your server. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your site runs on &lt;code&gt;localhost:3333&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You can access the functions at &lt;code&gt;localhost:3333/.netlify/functions/{YOUR_FUNCTION_NAME}&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;I include a sample function called &lt;code&gt;hello&lt;/code&gt; in this starter, which can be accessed at &lt;code&gt;localhost:3333/.netlify/functions/hello&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This function takes an optional &lt;code&gt;name&lt;/code&gt; query parameter, eg. &lt;code&gt;localhost:3333/.netlify/functions/hello?name=Eka&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Port &lt;code&gt;3333&lt;/code&gt; is configured in &lt;code&gt;netlify.toml&lt;/code&gt;. You can change it to any other value (as long as it does not clash with used ports).&lt;/p&gt;

&lt;p&gt;If you are not familiar with Netlify functions or &lt;code&gt;netlify dev&lt;/code&gt;, check out my post about getting started with Netlify functions.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ekafyi" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F70827%2F319e1725-cd9c-40c5-bbad-6e9be00879be.png" alt="ekafyi"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/ekafyi/getting-started-with-netlify-functions-part-1-zero-config-setup-and-writing-our-first-functions-1i5b" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Getting started with Netlify Functions — Zero-config setup and our first functions&lt;/h2&gt;
      &lt;h3&gt;Eka ・ Jul 25 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#serverless&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#jamstack&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;I’m working on a demo site that demonstrates how to use Netlify functions in this starter site, so watch this space!&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus Track
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/iZ9vkd7Rp-g"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>jamstack</category>
      <category>svelte</category>
      <category>junglejs</category>
    </item>
    <item>
      <title>Get asynchronous data in JungleJS, the new Svelte JAMstack library</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Tue, 28 Jul 2020 18:14:16 +0000</pubDate>
      <link>https://dev.to/ekafyi/get-asynchronous-data-in-junglejs-the-new-svelte-jamstack-library-1dkm</link>
      <guid>https://dev.to/ekafyi/get-asynchronous-data-in-junglejs-the-new-svelte-jamstack-library-1dkm</guid>
      <description>&lt;p&gt;&lt;a href="https://www.junglejs.org/" rel="noopener noreferrer"&gt;JungleJS&lt;/a&gt; is a new static site generator that uses Svelte and GraphQL. It also has a handy routing feature akin to NextJS and Sapper, where you can have &lt;code&gt;src/routes/[slug].svelte&lt;/code&gt; and query for data based on the &lt;code&gt;slug&lt;/code&gt;. I made this &lt;a href="https://github.com/ekafyi/junglejs-storybook-tailwind" rel="noopener noreferrer"&gt;JungleJS starter site with Storybook and Tailwind CSS&lt;/a&gt; so you can get started using it more quickly.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ekafyi" rel="noopener noreferrer"&gt;
        ekafyi
      &lt;/a&gt; / &lt;a href="https://github.com/ekafyi/junglejs-storybook-tailwind" rel="noopener noreferrer"&gt;
        junglejs-storybook-tailwind
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Starter site for JungleJS + Storybook + TailwindCSS
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;At the time of writing, the official &lt;a href="https://www.junglejs.org/docs/config/" rel="noopener noreferrer"&gt;docs&lt;/a&gt; and &lt;a href="https://github.com/junglejs/template" rel="noopener noreferrer"&gt;template&lt;/a&gt; describe &lt;em&gt;two data sources&lt;/em&gt;: JSON (whether imported and parsed from local files or written in the JS code) and Markdown files. All well and good if you only need those data sources. But many websites today also get their data from external sources by sending a request to an external API, which is asynchronous in nature.&lt;/p&gt;

&lt;p&gt;This is not possible with the current template, so I asked on their Github repo: &lt;strong&gt;Is it possible to fetch data asynchronously in JungleJS?&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/junglejs/junglejs/issues/10" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Is it possible to pass data to dataSources asynchronously?
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#10&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/ekafyi" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars2.githubusercontent.com%2Fu%2F6597211%3Fv%3D4" alt="ekafyi avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/ekafyi" rel="noopener noreferrer"&gt;ekafyi&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/junglejs/junglejs/issues/10" rel="noopener noreferrer"&gt;&lt;time&gt;Jul 26, 2020&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Trying JungleJS for the first time now, good work!&lt;/p&gt;
&lt;p&gt;I wonder if it's possible to query data from an external source (eg. &lt;code&gt;fetch&lt;/code&gt; from external API) then pass it to &lt;code&gt;dataSources&lt;/code&gt; &lt;code&gt;items&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;The problem is, it has to be done asynchronously. Is it possible at all to return &lt;code&gt;exports&lt;/code&gt; in &lt;code&gt;jungle.config.js&lt;/code&gt; asynchronously? Or is there any other way to achieve this?&lt;/p&gt;
&lt;p&gt;Thanks!&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/junglejs/junglejs/issues/10" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;They responded that they aimed to have this functionality as a user-facing plugin in the future, and kindly gave the code to run JungleJS asynchronously in the meantime.&lt;/p&gt;

&lt;p&gt;To save you all the copy-pasting and server-restarting 😉, I added a simple example and published it to my starter site under the branch &lt;code&gt;with-async-data&lt;/code&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/ekafyi/junglejs-storybook-tailwind/tree/with-async-data" rel="noopener noreferrer"&gt;JungleJS + Storybook + Tailwind CSS starter with asynchronous data fetching example&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Clone: &lt;code&gt;git clone -b with-async-data https://github.com/ekafyi/junglejs-storybook-tailwind.git&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com/import/git?s=https%3A%2F%2Fgithub.com%2Fekafyi%2Fjunglejs-storybook-tailwind%2Ftree%2Fwith-async-data" rel="noopener noreferrer"&gt;Deploy with Vercel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://junglejs-async-demo.netlify.app" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you use the Netlify Deploy button or the Github template feature, you’ll get the &lt;code&gt;master&lt;/code&gt; branch by default. You can run &lt;code&gt;git checkout with-async-data&lt;/code&gt; to move to the async branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I made this example
&lt;/h2&gt;

&lt;p&gt;First I modified &lt;code&gt;app.js&lt;/code&gt; to run asynchronously as advised by &lt;a href="https://github.com/ConProgramming" rel="noopener noreferrer"&gt;@ConProgramming&lt;/a&gt;, the creator, in the issue’s answer above. I did the same with &lt;code&gt;build.js&lt;/code&gt;. (Not in the original answer but this is also necessary.)&lt;/p&gt;

&lt;p&gt;Next I modified &lt;code&gt;jungle.config.js&lt;/code&gt;, which previously exported an object, into an asynchronous function as per the answer. Then I added a simple fetch example with the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npm i -D node-fetch&lt;/code&gt; (install and save the node-fetch package as dev dependency). You can use eg. &lt;code&gt;axios&lt;/code&gt; instead of fetch if you want.&lt;/li&gt;
&lt;li&gt;Fetch data from the free &lt;a href="https://openlibrary.org/developers/api" rel="noopener noreferrer"&gt;OpenLibrary API&lt;/a&gt;. You can replace it with any API you want; simply change the &lt;code&gt;SAMPLE_FETCH_URL&lt;/code&gt; value.

&lt;ul&gt;
&lt;li&gt;Don’t forget to add the necessary credentials or headers in your request as required by the API.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Pass the returned data to the &lt;code&gt;dataSources&lt;/code&gt; in the same format as the existing data source objects example.
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// jungle.config.js&lt;/span&gt;

&lt;span class="c1"&gt;// ... other stuff&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node-fetch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SAMPLE_FETCH_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://some-external-api/endpoint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SAMPLE_FETCH_URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;myResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// .. clientInputOptions etc&lt;/span&gt;
    &lt;span class="na"&gt;dataSources&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;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;book&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// data name as a singleton noun&lt;/span&gt;
        &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;myArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// our data as an array&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;// ... other data sources&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;



&lt;p&gt;Then the data is processed into the GraphQL layer and available to query from our frontend. As I use the name &lt;code&gt;book&lt;/code&gt; in &lt;code&gt;jungle.config.js&lt;/code&gt; &lt;code&gt;dataSources&lt;/code&gt;, I use the plural format &lt;code&gt;books&lt;/code&gt; to get a list of books via GraphQL query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;QUERY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    query {
      books {
        authors {
          name
        }
        cover {
          medium
        }
        title
        url
      }
    }
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;QUERYRES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;QUERYRES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data is available as &lt;code&gt;QUERYRES.books&lt;/code&gt; and can be used as we normally would in any Svelte application. This is the simplified version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{#each QUERYRES.books as {authors, cover, subtitle, title, url}}
  &lt;span class="nt"&gt;&amp;lt;article&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;{cover.medium}&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"180"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"270"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;{`${title}${subtitle ? `: ${subtitle}` : ''}`}&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{joinAuthorNames(authors)}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
{/each}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To build for production, run &lt;code&gt;npm run build&lt;/code&gt;. The build is in the &lt;code&gt;jungle/build&lt;/code&gt; directory, ready to upload/drop to any static site hosting you want. I use &lt;a href="https://app.netlify.com" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;, where I can drag and drop the folder and have &lt;a href="https://junglejs-async-demo.netlify.app/" rel="noopener noreferrer"&gt;my Jungle site&lt;/a&gt; live in a few seconds. ✨&lt;/p&gt;

&lt;h2&gt;
  
  
  My impressions of JungleJS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🙂 Like
&lt;/h3&gt;

&lt;p&gt;I love Jungle’s approach to SSG. Powered by Svelte, it creates a lean, no-frills, modern JAMstack site with no redundant hydration or run-time tasks. It’s idea for websites where we don’t need complex client-side features and would like more control to add progressive enhancements as we see fit.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effortlessly good SEO:&lt;/strong&gt; You can &lt;em&gt;“View Page Source”&lt;/em&gt; on the page and see our books data rendered as regular HTML, ready for search engines to crawl.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effortlessly good Lighthouse score:&lt;/strong&gt; As shown below, it literally loads the HTML, 2 CSS files, 1 bundled JS file, and the images. That’s it.&lt;/li&gt;
&lt;/ul&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%2Fn9frxdmlg7ryqomgapwx.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%2Fn9frxdmlg7ryqomgapwx.png" alt="screenshot of demo site with DevTools Network tab open showing what assets are loaded"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is simply a quick demo. For production, the images should ideally be lazy-loaded, the 2 CSS files combined and/or lazy-loaded, and the JS file deferred for better performance.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🙁 Dislike
&lt;/h3&gt;

&lt;p&gt;Not reallly a “dislike” per se, but given this library is very new, the development experience is still not ideal. For starter there is no live reload, so you have to restart the server to see any change. Also, using GraphQL beyond simple data like in this example may be tricky.&lt;/p&gt;

&lt;p&gt;Gatsby, for example, has an integrated GraphQL viewer where we can check our query. They also provide a way to anticipate missing data that would otherwise break the GraphQL query (for example, querying for the optional &lt;code&gt;subtitle&lt;/code&gt; field would break if none of the books have a &lt;code&gt;subtitle&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Until then, feel free to try the starter and hope JungleJS grows into a more mature library. 😃🤞&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus Track
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/o1tj2zJ2Wvg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>jamstack</category>
      <category>svelte</category>
      <category>junglejs</category>
    </item>
    <item>
      <title>JungleJS + Storybook + TailwindCSS starter</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Sun, 26 Jul 2020 19:32:32 +0000</pubDate>
      <link>https://dev.to/ekafyi/junglejs-storybook-tailwindcss-starter-site-3dmf</link>
      <guid>https://dev.to/ekafyi/junglejs-storybook-tailwindcss-starter-site-3dmf</guid>
      <description>📷 Cover image: &lt;a href="https://unsplash.com/@isaacquesada?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="external noopener noreferrer"&gt;Isaac Quesada&lt;/a&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ekafyi" rel="noopener noreferrer"&gt;
        ekafyi
      &lt;/a&gt; / &lt;a href="https://github.com/ekafyi/junglejs-storybook-tailwind" rel="noopener noreferrer"&gt;
        junglejs-storybook-tailwind
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Starter site for JungleJS + Storybook + TailwindCSS
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;JungleJS + Storybook + TailwindCSS starter site&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/e34f1b5abe9e1e3def583eb56fb3ac8d3a741f68313bec4d24bcb99674f5bede/68747470733a2f2f696d6167652e666c617469636f6e2e636f6d2f69636f6e732f7376672f323935302f323935303533322e737667"&gt;&lt;img src="https://camo.githubusercontent.com/e34f1b5abe9e1e3def583eb56fb3ac8d3a741f68313bec4d24bcb99674f5bede/68747470733a2f2f696d6167652e666c617469636f6e2e636f6d2f69636f6e732f7376672f323935302f323935303533322e737667" width="120" height="120" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A starter site for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.junglejs.org" rel="nofollow noopener noreferrer"&gt;JungleJS&lt;/a&gt; — Svelte and GraphQL-based static site generator&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://storybook.js.org" rel="nofollow noopener noreferrer"&gt;Storybook&lt;/a&gt; — UI development environment&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tailwindcss.com" rel="nofollow noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; — utility-first CSS framework&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Read my introduction posts on DEV:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/ekafyi/junglejs-storybook-tailwindcss-starter-site-3dmf" rel="nofollow"&gt;JungleJS + Storybook + TailwindCSS starter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/ekafyi/get-asynchronous-data-in-junglejs-the-new-svelte-jamstack-library-1dkm" rel="nofollow"&gt;Get asynchronous data in JungleJS, the new Svelte JAMstack library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Branches&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ekafyi/junglejs-storybook-tailwind/tree/master" rel="noopener noreferrer"&gt;master&lt;/a&gt; — JungleJS + Storybook + Tailwind CSS&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ekafyi/junglejs-storybook-tailwind/tree/with-async-data" rel="noopener noreferrer"&gt;with-async-data&lt;/a&gt; — master + async data fetching example&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick start&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://vercel.com/import/git?s=https%3A%2F%2Fgithub.com%2Fekafyi%2Fjunglejs-storybook-tailwind%2Ftree%2Fmaster" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/20bea215d35a4e28f2c92ea5b657d006b087687486858a40de2922a4636301ab/68747470733a2f2f76657263656c2e636f6d2f627574746f6e" alt="Deploy with Vercel"&gt;&lt;/a&gt; &lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/ekafyi/junglejs-storybook-tailwind" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ef0cc1d083b2d67eb72500031401d9b52c3ecb9fb4c4405f46afd0d0aba02d6/68747470733a2f2f7777772e6e65746c6966792e636f6d2f696d672f6465706c6f792f627574746f6e2e737667" alt="Deploy with Netlify"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Or &lt;a href="https://github.com/ekafyi/junglejs-storybook-tailwind/generate" rel="noopener noreferrer"&gt;create a new repo&lt;/a&gt; with Github template.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install and develop&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Install the global Netlify CLI package if you haven’t&lt;/span&gt;
npm install netlify-cli -g

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Clone and go to project directory&lt;/span&gt;
git clone https://github.com/ekafyi/junglejs-storybook-tailwind.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; junglejs-storybook-tailwind

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Install dependencies&lt;/span&gt;
npm install

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Start Jungle server&lt;/span&gt;
npm run start

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Start Storybook server&lt;/span&gt;
npm run storybook&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Jungle runs on &lt;code&gt;localhost:3000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Storybook runs on &lt;code&gt;localhost:6006&lt;/code&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Directory structure&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;root
├── .storybook &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Storybook config&lt;/span&gt;
├── src
│   ├── &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; ...&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ekafyi/junglejs-storybook-tailwind" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://www.junglejs.org/" rel="noopener noreferrer"&gt;JungleJS&lt;/a&gt; is a new static site generator. All &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; goodness + &lt;a href="https://graphql.org/" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt; data layer = fast, performant static site. Jungle’s underlying philosophy seems to resemble Eleventy, except Jungle uses Svelte. &lt;/p&gt;

&lt;p&gt;But as of now, Jungle does not have live reload yet. We have to restart the server any time we make a change. While only partially addressing the needs for live reload, we can use &lt;a href="https://storybook.js.org/" rel="noopener noreferrer"&gt;Storybook&lt;/a&gt; for developing UI components. Even in project with hot reloading/live reload, it’s useful to have an isolated UI development environment like Storybook, which also provides us with &lt;a href="https://storybook.js.org/addons/" rel="noopener noreferrer"&gt;various addons&lt;/a&gt;, from accessibility to testing. Finally, &lt;a href="http://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind&lt;/a&gt; provides customizable, utility-first CSS, which helps us build our UI faster.&lt;/p&gt;

&lt;p&gt;And thus &lt;a href="https://github.com/ekafyi/junglejs-storybook-tailwind" rel="noopener noreferrer"&gt;this starter site&lt;/a&gt; was born.&lt;/p&gt;

&lt;p&gt;For a quick start, you can click the “Use this template” button on the Github repository or run &lt;code&gt;git clone https://github.com/ekafyi/junglejs-storybook-tailwind.git&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let me know if you're building anything with this!&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus track
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/OQlByoPdG6c"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>svelte</category>
      <category>junglejs</category>
    </item>
    <item>
      <title>Getting started with Netlify Functions — Zero-config setup and our first functions</title>
      <dc:creator>Eka</dc:creator>
      <pubDate>Sat, 25 Jul 2020 16:55:44 +0000</pubDate>
      <link>https://dev.to/ekafyi/getting-started-with-netlify-functions-part-1-zero-config-setup-and-writing-our-first-functions-1i5b</link>
      <guid>https://dev.to/ekafyi/getting-started-with-netlify-functions-part-1-zero-config-setup-and-writing-our-first-functions-1i5b</guid>
      <description>&lt;p&gt;&lt;strong&gt;Serverless functions&lt;/strong&gt; are server-side functions that are hosted on a third-party service (in this case Netlify). In a nutshell, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We write our server-side functions&lt;/li&gt;
&lt;li&gt;We walk up to the third-party service with the functions and say, &lt;em&gt;“Oh hey, could you please run these for me on your server?”&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;They say &lt;em&gt;“Sure!”&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;We can now call the functions to do whatever they are supposed to do and return whatever we need for our web application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; With serverless functions, we get the benefits of a server without having our own server. Our “server-side” functions can even live in the same codebase as our website code. How convenient! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use these?&lt;/strong&gt; In my opinion, this is ideal for small to mid-level projects. If your app has large traffic or other specific/unusual requirements, make sure to compare the costs and implications thoroughly before going serverless. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A misnomer?&lt;/strong&gt; Much like wireless speakers are &lt;em&gt;not without wires&lt;/em&gt;, these functions definitely run on servers; we just don’t need to set up, configure, host, and manage them ourselves. 😁&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/qPcX2mzk3NmjC/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img alt="Finn from the cartoon Adventure Time doing a thumbs-up with the text Niiiiice" src="https://i.giphy.com/media/qPcX2mzk3NmjC/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this series, we’re going to learn how Netlify functions work by building a web application with a REST API from scratch and deploy it. It’s inspired by Jason Lengstorf’s &lt;a href="https://frontendmasters.com/workshops/serverless-functions/" rel="noopener noreferrer"&gt;“Introduction to Serverless Functions” workshop&lt;/a&gt;, which was my first encounter with serverless functions.&lt;/p&gt;

&lt;p&gt;This first post focuses on getting our local dev environment up and writing our first functions. Before we proceed, please note this post presumes the following.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic knowledge in:

&lt;ul&gt;
&lt;li&gt;JavaScript and HTML&lt;/li&gt;
&lt;li&gt;How a web application works (server, client/browser)&lt;/li&gt;
&lt;li&gt;RESTful API&lt;/li&gt;
&lt;li&gt;Git version control&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;A (free) account on:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, &lt;a href="https://about.gitlab.com/" rel="noopener noreferrer"&gt;GitLab&lt;/a&gt;, or &lt;a href="https://bitbucket.org/product" rel="noopener noreferrer"&gt;Bitbucket&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Latest node and npm (run &lt;code&gt;node -v &amp;amp;&amp;amp; npm -v&lt;/code&gt; on your CLI/Terminal to check)&lt;/li&gt;

&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Installation&lt;/li&gt;
&lt;li&gt;Start our development environment&lt;/li&gt;
&lt;li&gt;Create our server(less) functions

&lt;ul&gt;
&lt;li&gt;3a. Define our functions directory&lt;/li&gt;
&lt;li&gt;3b. Add function files to our functions directory&lt;/li&gt;
&lt;li&gt;3c. Write our first function&lt;/li&gt;
&lt;li&gt;3d. Write a function with query string parameters&lt;/li&gt;
&lt;li&gt;3e. Write a function that accepts a data body (payload)&lt;/li&gt;
&lt;li&gt;3f. Use secret environment variables in our function&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Installation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1a. Install the global Netlify CLI package
&lt;/h3&gt;

&lt;p&gt;Run on your command line: &lt;code&gt;npm install netlify-cli -g&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1b. Prepare your web app
&lt;/h3&gt;

&lt;p&gt;Clone or initialize your project. You can clone this sample repo for a quick start.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone -b part-1 https://github.com/ekafyi/hello-serverless-netlify-functions.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Netlify functions are written in standard (vanilla) JS and work with any modern JS libraries. The sample repo uses the &lt;a href="https://www.11ty.dev/docs/getting-started/" rel="noopener noreferrer"&gt;default Eleventy installation&lt;/a&gt;. We're not going to write any web code yet, but feel free to use a starter from your favourite library instead.&lt;/p&gt;

&lt;p&gt;Don’t forget to &lt;code&gt;cd&lt;/code&gt; to the project directory and install the project’s dependencies by running &lt;code&gt;yarn&lt;/code&gt; or &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Start our development environment
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;netlify dev&lt;/code&gt; (or &lt;code&gt;ntl dev&lt;/code&gt; for short) to start our local development environment. It’s going to serve our web app (in my case Eleventy), our web server, and a Browsersync interface.&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%2F59a1dvlx7y8rs4otzdsy.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%2F59a1dvlx7y8rs4otzdsy.png" alt="ntl dev serving 3 URLs in the CLI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our web app runs on port &lt;code&gt;8080&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;This our web app’s dev server that we usually start with &lt;code&gt;npm run start&lt;/code&gt; or &lt;code&gt;npm run watch&lt;/code&gt; (or the &lt;code&gt;yarn&lt;/code&gt; equivalent).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Browsersync UI runs on port &lt;code&gt;3001&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Our web server runs on port &lt;code&gt;8888&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you cloned the sample repo, you should see this page on both ports &lt;code&gt;8080&lt;/code&gt; and &lt;code&gt;8888&lt;/code&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%2F7c7kw23aobtkwpxpj5oo.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%2F7c7kw23aobtkwpxpj5oo.png" alt="web app home page"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  What kind of sorcery is this? 🧙🏼‍♀️✨
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.netlify.com/products/dev/" rel="noopener noreferrer"&gt;Netlify Dev&lt;/a&gt; is an integrated local development environment that automatically:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Detects and runs your site generator&lt;/li&gt;
&lt;li&gt;Makes environment variables available&lt;/li&gt;
&lt;li&gt;Performs edge logic and routing rules&lt;/li&gt;
&lt;li&gt;Compiles and runs cloud functions&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;It has a “project detector” that checks our project &lt;code&gt;package.json&lt;/code&gt; and configures the dev setup automatically. In most cases, it “just works”—no need to do anything. &lt;/p&gt;

&lt;p&gt;However, if you use a less popular library and/or have a custom setup, you can declare your setup by creating a &lt;code&gt;netlify.toml&lt;/code&gt; file in your project root that contains your dev setup.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# netlify.toml dev block example&lt;/span&gt;
&lt;span class="nn"&gt;[dev]&lt;/span&gt;
  &lt;span class="py"&gt;command&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"yarn dev"&lt;/span&gt;
  &lt;span class="py"&gt;port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Learn more:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.netlify.com/blog/2019/04/24/zero-config-yet-technology-agnostic-how-netlify-dev-detectors-work/" rel="noopener noreferrer"&gt;Zero Config, yet Technology Agnostic: How Netlify Dev Detectors Work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;List of built-in detectors &lt;a href="https://github.com/netlify/cli/tree/master/src/detectors" rel="noopener noreferrer"&gt;https://github.com/netlify/cli/tree/master/src/detectors&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Netlify Dev documentation &lt;a href="https://github.com/netlify/cli/blob/master/docs/netlify-dev.md" rel="noopener noreferrer"&gt;https://github.com/netlify/cli/blob/master/docs/netlify-dev.md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you run extra servers for custom processes (eg. to watch CSS with Sass or PostCSS), you still need to run them separately in addition to &lt;code&gt;ntl dev&lt;/code&gt;, OR modify your &lt;code&gt;package.json&lt;/code&gt; so they are included in the default dev command.&lt;/p&gt;

&lt;p&gt;Now we’ve got our web app running, let’s write our first functions!&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Create our server(less/-side) functions
&lt;/h2&gt;

&lt;p&gt;📝 &lt;strong&gt;Note:&lt;/strong&gt; &lt;a href="https://docs.netlify.com/functions/overview/" rel="noopener noreferrer"&gt;Netlify Docs&lt;/a&gt; has in-depth explanation on the functions discussed here.&lt;/p&gt;
&lt;h3&gt;
  
  
  3a. Define our functions directory
&lt;/h3&gt;

&lt;p&gt;I create a new directory called &lt;code&gt;functions&lt;/code&gt; in my project root. (You can use any name; make sure to specify the right name below.)&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;netlify.toml&lt;/code&gt; in your project root (if you don’t have it already) and add &lt;code&gt;functions=""&lt;/code&gt; inside the &lt;code&gt;[dev]&lt;/code&gt; block, where the value is the name of our serverless functions directory (in my case, &lt;code&gt;functions&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# netlify.toml&lt;/span&gt;
&lt;span class="nn"&gt;[dev]&lt;/span&gt;
  &lt;span class="py"&gt;command&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"npm run build"&lt;/span&gt;
  &lt;span class="py"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_site"&lt;/span&gt;
  &lt;span class="py"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"functions"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  3b. Add function files to our functions directory
&lt;/h3&gt;

&lt;p&gt;Next, create a JS file in our functions directory that exports a &lt;code&gt;handler&lt;/code&gt; method. (I use the ES6 syntax here, hence &lt;code&gt;() =&amp;gt; { … }&lt;/code&gt; instead of &lt;code&gt;function() { … }&lt;/code&gt;. Feel free to use whichever you’re most comfortable with.)&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// functions/hello.js&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... later&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The filename without extension represents a serverless function endpoint in this format: &lt;code&gt;{SERVER_URL}/.netlify/functions/{FUNCTION_NAME}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, if we have &lt;code&gt;functions/hello.js&lt;/code&gt;, we send our request to &lt;code&gt;http://localhost:8888/.netlify/functions/hello&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We can have as many files as we want.&lt;/p&gt;
&lt;h3&gt;
  
  
  3c. Write our first function
&lt;/h3&gt;

&lt;p&gt;Our function should return a JSON response. This is the most simple function possible.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// functions/hello.js&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello there!&lt;/span&gt;&lt;span class="dl"&gt;"&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;span class="c1"&gt;// GET localhost:8888/.netlify/functions/hello&lt;/span&gt;
&lt;span class="c1"&gt;// → Hello there!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;async&lt;/code&gt; means this is an asynchronous function, which I can call from my web app code with a &lt;em&gt;promise&lt;/em&gt;. If you’re not familiar with these, read &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Introducing" rel="noopener noreferrer"&gt;“Introducing asynchronous JavaScript“ on MDN&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;List of &lt;a href="https://httpstatuses.com/" rel="noopener noreferrer"&gt;HTTP response status codes&lt;/a&gt; (maybe don’t return &lt;a href="https://httpstatuses.com/418" rel="noopener noreferrer"&gt;418&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3d. Write a function with query string parameters
&lt;/h3&gt;

&lt;p&gt;The handler method has the &lt;code&gt;event&lt;/code&gt; and &lt;code&gt;context&lt;/code&gt; parameters, and an optional &lt;code&gt;callback&lt;/code&gt; parameter. The &lt;code&gt;event&lt;/code&gt; object contains information about the request. It looks like this.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/.netlify/functions/echo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"httpMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queryStringParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isBase64Encoded"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;path&lt;/code&gt; = path parameter&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;httpMethod&lt;/code&gt; = request’s method (eg. &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;As per the suggested &lt;a href="https://restfulapi.net/resource-naming/" rel="noopener noreferrer"&gt;RESTful API naming practices&lt;/a&gt;, GET &lt;code&gt;/.netlify/functions/users&lt;/code&gt; should get the users data and POST &lt;code&gt;/.netlify/functions/users&lt;/code&gt; should create a new user. We can do this in serverless functions by getting the &lt;code&gt;httpMethod&lt;/code&gt; value.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;headers&lt;/code&gt; = request headers

&lt;ul&gt;
&lt;li&gt;This contains HTTP Headers data such as &lt;code&gt;Accept-Language&lt;/code&gt;, &lt;code&gt;User-Agent&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;queryStringParameters&lt;/code&gt;  = self-explanatory (more on this below)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;body&lt;/code&gt; = request payload&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isBase64Encoded&lt;/code&gt; = a boolean flag to indicate if the applicable request payload is Base64-encode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let’s modify our &lt;code&gt;hello&lt;/code&gt; function to return a greeting based on the &lt;code&gt;name&lt;/code&gt; parameter in the request.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// functions/hello.js&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryStringParameters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stranger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&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;span class="c1"&gt;// GET localhost:8888/.netlify/functions/hello&lt;/span&gt;
&lt;span class="c1"&gt;// → Hello stranger!&lt;/span&gt;

&lt;span class="c1"&gt;// GET localhost:8888/.netlify/functions/hello?name=Eka&lt;/span&gt;
&lt;span class="c1"&gt;// → Hello Eka!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;We use the &lt;code&gt;event&lt;/code&gt; parameter and get the &lt;code&gt;name&lt;/code&gt; value from &lt;code&gt;event.queryStringParameters&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;Note: &lt;code&gt;const { name } = event.queryStringParameters&lt;/code&gt; is shorthand for &lt;code&gt;const name = event.queryStringParameters.name&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If we have multiple query string parameters in the request, we can access them all as objects in &lt;code&gt;queryStringParameters&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;eg. GET &lt;code&gt;localhost:8888/.netlify/functions/hello?name=Eka&amp;amp;timeOfDay=morning&lt;/code&gt;, we can get the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;timeOfDay&lt;/code&gt; values from &lt;code&gt;event.queryStringParameters&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are not discussing the &lt;code&gt;context&lt;/code&gt; and &lt;code&gt;callback&lt;/code&gt; parameters in this post, but you can read about them in the links below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn more:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.netlify.com/functions/build-with-javascript" rel="noopener noreferrer"&gt;Build serverless functions with JavaScript&lt;/a&gt; — Netlify Documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" rel="noopener noreferrer"&gt;HTTP headers&lt;/a&gt; — MDN Docs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3e. Write a function that accepts a data body (payload)
&lt;/h3&gt;

&lt;p&gt;POST requests are basically similar to GET requests, except they may contain data—eg. user-inputted form data—in the request body. We can access it in &lt;code&gt;event.body&lt;/code&gt; and do something with it, such as send it to some external API or database.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// functions/newsletter.js&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Request body data&lt;/span&gt;

  &lt;span class="c1"&gt;// Basic example of sending the data to an external API&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://someserver.com/v1/some/endpoint`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// Add credentials as required by the external service&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Send the data&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&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="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Do stuff and returns 200 response...&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Do stuff and returns 4xx / 5xx response...&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// POST localhost:8888/.netlify/functions/newsletter&lt;/span&gt;
&lt;span class="c1"&gt;// → 200 OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Remember that these functions &lt;em&gt;are&lt;/em&gt; regular JavaScript code. &lt;code&gt;body&lt;/code&gt; data are sent in JSON-safe string format; request &lt;code&gt;body&lt;/code&gt; must be &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse" rel="noopener noreferrer"&gt;parsed&lt;/a&gt; if we want to access it as JS objects, and contrariwise JS objects must be &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify" rel="noopener noreferrer"&gt;stringified&lt;/a&gt; to send in response &lt;code&gt;body&lt;/code&gt;. &lt;/p&gt;
&lt;h3&gt;
  
  
  3f. Use secret environment variables in our function
&lt;/h3&gt;

&lt;p&gt;We briefly discussed sending our data to an external service in the example above. Today, most web apps retrieve and/or send data to and from external APIs, usually with some kind of &lt;em&gt;secret&lt;/em&gt; (token or key) in our request header to validate our app.&lt;/p&gt;

&lt;p&gt;We &lt;em&gt;should not&lt;/em&gt; make this request from the client side (the browser), because everyone can open the browser dev tools and find your credentials 🙀, which then can be used for (eg.) deleting all your data or posting egregious content on your behalf.&lt;/p&gt;

&lt;p&gt;With serverless functions, we can have “server-side” code to handle this operation while keeping our credentials private. &lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;.env&lt;/code&gt; in your project root (if it does not exist yet) and add your secret there.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SPOTIFY_CLIENT_ID=xxxxxxxxx
SPOTIFY_CLIENT_SECRET=xxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The env data is available in our functions in &lt;code&gt;process.env&lt;/code&gt; like so.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// functions/spotify.js&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Example of Spotify API "Client Credentials" authorization&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://accounts.spotify.com/api/token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/x-www-form-urlencoded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Basic &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;btoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SPOTIFY_CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SPOTIFY_CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;grant_type=client_credentials&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&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="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Do stuff ...&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Do stuff ...&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;Make sure &lt;code&gt;.env&lt;/code&gt; is in your &lt;code&gt;.gitignore&lt;/code&gt;  so it does not get pushed to the repository.&lt;/p&gt;
&lt;h2&gt;
  
  
  That’s all for now…
&lt;/h2&gt;

&lt;p&gt;You can see the sample repo below and the &lt;a href="https://hello-serverless-netlify-functions-one.netlify.app/" rel="noopener noreferrer"&gt;demo site here&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ekafyi" rel="noopener noreferrer"&gt;
        ekafyi
      &lt;/a&gt; / &lt;a href="https://github.com/ekafyi/hello-serverless-netlify-functions" rel="noopener noreferrer"&gt;
        hello-serverless-netlify-functions
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Sample repo for my “Getting Started with Netlify Functions” posts
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Hello Netlify Functions&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Sample repo for the first post in my “Getting Started with Netlify Functions” series.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/ekafyi/getting-started-with-netlify-functions-part-1-zero-config-setup-and-writing-our-first-functions-2257-temp-slug-5265523" rel="nofollow"&gt;View post on DEV.to&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website - &lt;a href="https://hello-serverless-netlify-functions-one.netlify.app" rel="nofollow noopener noreferrer"&gt;https://hello-serverless-netlify-functions-one.netlify.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Function
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hello-serverless-netlify-functions-one.netlify.app/.netlify/functions/hello" rel="nofollow noopener noreferrer"&gt;https://hello-serverless-netlify-functions-one.netlify.app/.netlify/functions/hello&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hello-serverless-netlify-functions-one.netlify.app/.netlify/functions/hello?name=Eka" rel="nofollow noopener noreferrer"&gt;https://hello-serverless-netlify-functions-one.netlify.app/.netlify/functions/hello?name=Eka&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hello-serverless-netlify-functions-one.netlify.app/.netlify/functions/hello?name=Jane%20Doe" rel="nofollow noopener noreferrer"&gt;https://hello-serverless-netlify-functions-one.netlify.app/.netlify/functions/hello?name=Jane%20Doe&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ekafyi/hello-serverless-netlify-functions" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;We have set up our project’s local development environment, written our first serverless functions, but you may notice we haven’t done anything with our web app. We’re going to do it in the next post, so stay tuned!&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus Track
&lt;/h2&gt;

&lt;p&gt;With serverless functions, you can send secrets in your requests securely. Here is my favourite (but unfortunately unreleased) version of “Secrets” by Strawberry Switchblade. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/knqqmGtmbhA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>jamstack</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
