<?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: Nicholas Cunningham</title>
    <description>The latest articles on DEV Community by Nicholas Cunningham (@ndcunningham).</description>
    <link>https://dev.to/ndcunningham</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%2F86438%2F6a1384e4-5f6e-4562-b363-1affc75a8a41.jpeg</url>
      <title>DEV Community: Nicholas Cunningham</title>
      <link>https://dev.to/ndcunningham</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ndcunningham"/>
    <language>en</language>
    <item>
      <title>Determine your User Location with Netlify Edge Functions</title>
      <dc:creator>Nicholas Cunningham</dc:creator>
      <pubDate>Fri, 26 May 2023 17:25:38 +0000</pubDate>
      <link>https://dev.to/nx/determine-your-user-location-with-netlify-edge-functions-2mn0</link>
      <guid>https://dev.to/nx/determine-your-user-location-with-netlify-edge-functions-2mn0</guid>
      <description>&lt;p&gt;Today, we will explore how to use &lt;code&gt;@nx/netlify&lt;/code&gt; serverless functions to determine a user's location. This can be an incredibly useful feature in various applications, such as customizing user experiences based on their region, displaying localized content, or tracking user demographics for marketing purposes. In this post, we'll walk you through a step-by-step guide on implementing this functionality using &lt;code&gt;@nx/netlify&lt;/code&gt; serverless functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Set up your Nx workspace with Netlify
&lt;/h2&gt;

&lt;p&gt;To get started, you need to have an Nx workspace. If you haven't already, create a new Nx workspace by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-nx-workspace user-location &lt;span class="nt"&gt;--preset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@nx/netlify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This should create a default function inside &lt;code&gt;src/functions/hello/hello.ts&lt;/code&gt;, which can be safely deleted if necessary.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Create a serverless function
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;src/functions/user-location
&lt;span class="nb"&gt;touch &lt;/span&gt;src/functions/user-location/user-location.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 3: Determine the user's location
&lt;/h2&gt;

&lt;p&gt;To determine the user's location, we will leverage the &lt;code&gt;request.headers&lt;/code&gt; object, specifically the &lt;code&gt;x-forwarded-for header&lt;/code&gt; containing the user's IP address. We can then use an IP geolocation API like ipapi (&lt;a href="https://ipapi.co/"&gt;https://ipapi.co/&lt;/a&gt;) to fetch location data based on this IP address.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt; In &lt;strong&gt;Node.js 18&lt;/strong&gt;, the experimental global fetch API is available by default. If you are a using node version &lt;strong&gt;lower&lt;/strong&gt; than &lt;strong&gt;18&lt;/strong&gt; you can install &lt;code&gt;node-fetch&lt;/code&gt; to handle API requests:&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;node-fetch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, update the &lt;code&gt;user-location.ts&lt;/code&gt; file with the following code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Handler&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="s1"&gt;@netlify/functions&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;fetch&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;node-fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Can be removed if node &amp;gt;= 18&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&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="nx"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ip&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;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-forwarded-for&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://ipapi.co/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/json/`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&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;response&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;fetch&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="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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&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="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="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;500&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;`Error fetching user location`&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;h2&gt;
  
  
  Step 4: Deploy your serverless function
&lt;/h2&gt;

&lt;p&gt;When we created our workspace, the initial scaffolding generated a &lt;strong&gt;deploy target&lt;/strong&gt; inside our &lt;code&gt;project.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;target&lt;/em&gt; is a specific task you can run for a project.&lt;br&gt;
You can think of it as a script/command that does a specific job. The most common targets are "build", "serve", "test", "lint", "deploy", etc. For more information regarding &lt;code&gt;project.json&lt;/code&gt; you can read about it at &lt;a href="https://nx.dev/reference/project-configuration"&gt;project-configuration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can start off by creating our site on Netlify by running:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx netlify init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After you have answered all the prompts your site should be created. A &lt;code&gt;.netlify&lt;/code&gt; folder should be created with references to your newly created site.&lt;/p&gt;

&lt;p&gt;Now, to deploy your serverless function run:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally, navigate to your Netlify site's Functions tab, and you should see your &lt;code&gt;user-location&lt;/code&gt; function deployed and ready to use!&lt;/p&gt;

&lt;p&gt;For example, ours can be found at: &lt;a href="https://644a9b17d0299b00b581b33f--find-user-location.netlify.app/.netlify/functions/user-location"&gt;https://644a9b17d0299b00b581b33f--find-user-location.netlify.app/.netlify/functions/user-location&lt;/a&gt;&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="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Miami"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Florida"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"US"&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;By following these steps, you've successfully used &lt;code&gt;@nx/netlify&lt;/code&gt; serverless function to determine a user's location!&lt;/p&gt;
&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Never used Nx before? Learn more about Nx &lt;a href="https://nx.dev/getting-started/why-nx"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nx.dev/recipes/deployment/node-serverless-functions-netlify#configure-your-netlify-deploy-settings"&gt;Official recipe from Nx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ndcunningham/nx-netlify-serverless"&gt;Github example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Learn more
&lt;/h2&gt;

&lt;p&gt;🧠 &lt;a href="https://nx.dev/"&gt;Nx Docs&lt;/a&gt;&lt;br&gt;
👩‍💻 &lt;a href="https://github.com/nrwl/nx"&gt;Nx GitHub&lt;/a&gt;&lt;br&gt;
💬 &lt;a href="https://go.nrwl.io/join-slack"&gt;Nrwl Community Slack&lt;/a&gt;&lt;br&gt;
📹 &lt;a href="https://www.youtube.com/@nxdevtools"&gt;Nrwl Youtube Channel&lt;/a&gt;&lt;br&gt;
🚀 &lt;a href="https://nx.app/"&gt;Speed up your CI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, if you liked this, click the ❤️ and make sure to follow &lt;a href="https://twitter.com/ndcunningham"&gt;Nicholas&lt;/a&gt; and &lt;a href="https://twitter.com/NxDevTools"&gt;Nx&lt;/a&gt; on Twitter for more!&lt;/p&gt;


&lt;div class="ltag__tag ltag__tag__id__18643"&gt;
    &lt;div class="ltag__tag__content"&gt;
      &lt;h2&gt;#&lt;a href="https://dev.to/t/nx" class="ltag__tag__link"&gt;nx&lt;/a&gt; Follow
&lt;/h2&gt;
      &lt;div class="ltag__tag__summary"&gt;
        
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
