Building A URL Shortener With Neon and Azure Serverless Functions

Building A URL Shortener With Neon and Azure Serverless Functions


Neon is now available on the Azure marketplace. The new integration between Neon and Azure allows you to manage your Neon subscription and billing through the Azure portal as if Neon were an Azure product. Azure serverless and Neon are a natural combination—Azure serverless frees you from managing your web server infrastructure. Neon does the same for databases, offering additional features like data branching and vector database extensions.

That said, let’s try out this new integration by building a URL shortener API with Neon, Azure serverless, and Node.js.

Note: You should have access to a terminal, an editor like VS Code, and Node v22 or later installed.



Setting up the infrastructure

We are going to have to do things a little backward today. Instead of writing the code, we will first first set up our serverless function and database.

Open up the Azure web portal. If you don’t already have one, you will need to create a Microsoft account.

You will also have to create a subscription if you don’t have one already, which you can do in Azure.

Now, we can create a resource group to store our serverless function and database. Go to Azure’s new resource group page and fill out the form like this:

This is the Azure Resource Group creation page with resource group set to “AzureNeonURLShortener” and location set to West US 3.

In general, use the location closest to you and your users, as the location will determine the default placement of serverless functions and what areas have the lowest latency. It isn’t vital in this example, but you can search through the dropdown if you want to use another. However, note that Neon doesn’t have locations in all of these regions yet, meaning you would have to place your database in a region further from your serverless function.

Click “Review & Create” at the bottom to access a configuration review page. Then click “Create” again.

Now, we can create the serverless function. Unfortunately, it includes another form. Go to the Azure Flex consumption serverless app creation page and complete the form.

Azure Flex consumption serverless app creation page

Use the resource group previously created, choose a unique serverless function name, place the function in your resource group region, and use Node v20.

The name you choose for your serverless app will be the subdomain Azure gives you to access your API, so choose wisely. After you finish filling everything out, click “Review and Create” and finally, “Create.” Azure should redirect you to the new app’s page. Now we can set up Neon. Open the new Neon Resource page on the Azure portal, and, you guessed it, fill out the form.

new Neon Resource page

Create a new Neon resource page with “AzureURLNeonShortener” as the resource group, “URLShortenerDB” as the resource name, and “West US 3” as the location. If the area you chose isn’t available, choose the next closest region. Once you complete everything, click “Review & Create” and then “Create,” as you did for previous resources.

You might have to wait a bit for the Neon database to instantiate. Once it does, open its configuration page and click “Go To Neon.”

Go To Neon

You will be redirected to a login page. Allow Neon to access your Azure information, and then you should find yourself on a project creation page. Fill out the form below:

Allow Neon to access your Azure information

The project and database name aren’t significant, but make sure to locate the database in Azure West US 3 (or whatever region you choose). This will prevent database queries from leaving the data center, decreasing latency.

Click “Create” at the bottom of the page, keeping the default autoscaling configuration. You should now be redirected to a Neon database page. This page has our connection string, which we will need to connect to our database from our code. Click “Copy snippet” to copy the connection string.

Copy Neon the connection string

Make sure you don’t lose this, as we will need it later, but for now, we need to structure our database. Click “SQL Editor” on the side navigation, and paste the following SQL in:

CREATE TABLE IF NOT EXISTS urls(id char(12) PRIMARY KEY, url TEXT NOT NULL);
Enter fullscreen mode

Exit fullscreen mode

Then click “Run.” This will create the table we will use to store URLs. The table is pretty simple: The primary key ID is a 12—character random string that we will use to refer to URLs, and the URL is a variable-length string that will store the URL itself.

URL is a variable-length string that will store the URL itself

If you look at the Table view on the side navigation, you should see a “urls” table. Finally, we need to get our connection string. Click on “Dashboard” on the side nav, find the connection string, and click “Copy snippet.”

Now, we can start writing code.



Building the API

First, we must install Azure’s serverless CLI, which will help us create a project and eventually test/publish it. Open a terminal and run:

npm install -g azure-functions-core-tools --unsafe-perm true
Enter fullscreen mode

Exit fullscreen mode

If you want to use other package managers like Yarn or pnpm, just replace npm with your preferred package manager. Now, we can start on our actual project. Open the folder you want the project to be in and run the following three commands:

func init --javascript
func new --name submit --template "HTTP trigger"
func new --name url --template "HTTP trigger"
npm install nanoid @neondatabase/serverless
Enter fullscreen mode

Exit fullscreen mode

Now, you should see a new Azure project in that folder. The first command creates the project, the two following commands create our serverless API routes, and the final command installs the Neon serverless driver for interfacing with our database and Nano ID for generating IDs. We could use a standard Postgres driver instead of the Neon driver, but Neon’s driver uses stateless HTTP queries to reduce latency for one-off queries. Because we are running a serverless function that might only process one request and send one query, one-off query latency is important.

You will want to focus on the code in src/functions, as that is where our routes are. You should see two files ther:, submit.js and redirect.js.



submit.js

submit.js will store the code we use to submit URLs. First, open submit.js and replace its code with the following:

import { app } from "@azure/functions";
import { neon } from "@neondatabase/serverless";
import { nanoid } from "nanoid";

const sql = neon("[YOUR_POSTGRES_CONNECTION_STRING]");

app.http("submit", {
  methods: ["GET"],
  authLevel: "anonymous",
  route: "submit",
  handler: async (request, context) => {
    if (!request.query.get("url"))
      return {
        body: "No url provided",
        status: 400,
      };
    if (!URL.canParse(request.query.get("url")))
      return {
        body: "Error parsing url",
        status: 400,
      };
    const id = nanoid(12);
    await sql`INSERT INTO urls(id,url) VALUES (${id},${request.query.get(
      "url"
    )})`;
    return new Response(`Shortened url created with id ${id}`);
  },
});
Enter fullscreen mode

Exit fullscreen mode

Let’s break this down step by step. First, we import the Azure functions API, Neon serverless driver and Nano ID.Wee are using ESM (ES Modules) here instead of CommonJS. We will need to make a few changes later on to support this.

Next, we create the connection to our database. Replace [YOUR_POSTGRES_CONNECTION_STRING] with the string you copied from the Neon dashboard. For security reasons, you would likely want to use a service like Azure Key Vault to manage your keys in a production environment, but for now, just placing them in the script will do.

Now, we are at the actual route. The first few properties define when our route handler should be triggered: We want this route to be triggered by a GET request to submit.

Our handler is pretty simple. We first check if a URL has been passed through the URL query parameter (e.g., /submit?url=https://google.com), then we check whether it is a valid URL via the new URL.canParse API. Next, We generate the ID with Nano ID. Because our IDs are 12 characters long, we have to pass 12 to the Nano ID generator. Finally, we insert a new row with the new ID and URL into our database. The Neon serverless driver automatically parameterizes queries, so we don’t need to worry about malicious users passing SQL statements into the URL.



redirect.js

redirect.js is where our actual URL redirects will happen. Replace its code with the following:

import { app } from "@azure/functions";
import { neon } from "@neondatabase/serverless";

const sql = neon("[YOUR_POSTGRES_CONNECTION_STRING]");

app.http("redirect", {
  methods: ["GET"],
  authLevel: "anonymous",
  route: "{id:length(12)}",
  handler: async (request, context) => {
    const url =
      await sql`SELECT * FROM urls WHERE urls.id=${request.params.id}`;
    if (!url[0]) return new Response("No redirect found", { status: 404 });

    return Response.redirect(url[0].url, 308);
  },
});
Enter fullscreen mode

Exit fullscreen mode

The first section of the script is the same as submit.js. Once again, replace [YOUR_POSTGRES_CONNECTION_STRING] with the string you copied from the Neon dashboard.

The route is where things get more interesting. We need to accept any path that could be a redirect ID, so we use a parameter with the constraint of 12 characters long. Note that this could overlap if you ever have another 12-character route. If it does, you can rename the redirect route to start with a Z or other alphanumerically greater character to make Azure serverless load the redirect route after.

Finally, we have our actual handler code. All we need to do here is query for a URL matching the given ID and redirect to it if one exists. We use the 308 status code in our redirect to tell browsers and search engines to ignore the original shortened URL.



Config files

There are two more changes we need to make. First, we don’t want a /api prefix on all our functions. To remove this, open host.json, which should be in your project directory, and add the following:

"extensions": {
    "http": {
      "routePrefix": ""
    }
  }
Enter fullscreen mode

Exit fullscreen mode

This allows your routes to operate without any prefixes. The one other thing we need to do is switch the project to ES Modules. Open package.json and insert the following at the end of the file:

"type": "module"
Enter fullscreen mode

Exit fullscreen mode

That’s it!



Testing & Deploying

Now, you can try testing locally by running func start. You can navigate to http://localhost:7071/submit?url=https://example.com, then use the ID it gives you and navigate to http://localhost:7071/[YOUR_ID]. You should be redirected to example.com.

Of course, we can’t just run this locally. To deploy, we need to install the Azure CLI, which you can do with one of the following commands, depending on your operating system:

macOS (Homebrew)

brew install azure-cli
Enter fullscreen mode

Exit fullscreen mode

Windows (WPM)

winget install -e --id Microsoft.AzureCLI
Enter fullscreen mode

Exit fullscreen mode

Linux

curl -L <https://aka.ms/InstallAzureCli> | bash
Enter fullscreen mode

Exit fullscreen mode

Now, restart the terminal, log in by running az login, and run the following in the project directory:

func azure functionapp publish [FunctionAppName]
Enter fullscreen mode

Exit fullscreen mode

Replace [FunctionAppName] with whatever you named your function earlier.

Now, you should be able to access your API at [FunctionAppName].azurewebsites.net.

You should now have a fully functional URL Shortener. You can access the code here and work on adding a front end. If you want to keep reading about Neon and Azure’s features, we recommend checking out Branching. Either way, I hope you learned something valuable from this guide.



Source link
lol

By stp2y

Leave a Reply

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

No widgets found. Go to Widget page and add the widget in Offcanvas Sidebar Widget Area.