Intro to Serverless Functions
Tags: serverless, javascript, netlify, functions
Published: 2022-07-25 12:30:53

---
title: Intro to Serverless Functions
published: true
description: Serverless does not mean there are no servers, it is essentially servers as a service. They allow you to run server side logic without maintaining a physical server.
tags: serverless, javascript, netlify, functions
cover_image: https://cdn.sanity.io/images/o0o2tn5x/production/0479a8ba5ff9cc31ff2b0905f55b6e7d718e2715-1200x630.png?w=2000&fit=max&auto=format&dpr=2
canonical_url: https://www.netlify.com/blog/intro-to-serverless-functions/
# Use a ratio of 100:42 for best results.
---

Serverless is a term we hear a lot in this industry, but what does serverless really mean? Serverless doesn’t really mean you don’t have servers, it’s more like servers as a service. Instead of owning and maintaining your own servers, you let a service do the work for you. You can focus on the business needs and developing a better quality application instead of worrying about the infrastructure and maintenance of a traditional server.

> *Serverless functions give developers superpowers and enables them to do things that would not otherwise have been possible. —Jason Lengstorf*
> 

## Serverless Functions on Netlify

Serverless functions, branded as [Netlify Functions](https://www.netlify.com/products/functions) when running on Netlify, are a way to deploy server-side code as API endpoints. These will spin up automatically when triggered by an event, handle and process server ran code, and then spin down until the next event. Using Netlify for your serverless functions creates a seamless workflow that allows you to write and test your functions locally with the [Netlify CLI](https://www.netlify.com/products/cli/), build and deploy your applications, and avoid the setup, cost, and maintenance of a physical server.

On Netlify, there are several options when it comes to using serverless functions. This post is going to focus on [traditional serverless functions](#traditional-serverless-functions), but you may also want to explore [background functions](https://www.netlify.com/blog/2021/01/07/what-are-background-functions/) or the new [edge functions](https://www.netlify.com/blog/edge-functions-explained/) that can be distributed closer to your users.

### Traditional Serverless Functions

What’s thought of as a traditional serverless function, is a short running synchronous function written in JavaScript, TypeScript, or Go that is hosted as an endpoint. It performs some server side code and then returns a response to the client immediately. These are AWS Lambda functions with a default region of `us-east-1`. They have a 10 second time limit and a memory limit of 1024 megabytes. 

Everything that we do in technology has a tradeoff, there are pros and cons no matter what it is. Let’s look at both for serverless functions.

### Pros

- lowers barrier to entry for devs
- inexpensive
- faster iteration
- quick deployments
- abstracts away the setup and maintenance of a physical server

### Cons

- not built for long running processes (10 sec limit)
- stateless - does not maintain data
- cold starts - referring to the time it takes to start up when a function is invoked or ephemeral containers

## Getting Started

Now we are going to walk through the steps to get a serverless function up and running on Netlify. To get started with this project, having some understanding of HTML, JavaScript, the command line, npm, and git will be helpful. Also, if you don’t already have a Netlify account, you can [sign up for free here](https://app.netlify.com/signup). 

### Project Setup

- Open the **[explorers up and running with serverless functions repository on Netlify’s GitHub](https://github.com/netlify/explorers-up-and-running-with-serverless-functions)**.
- Click the **Use this template** button in order to create this repo inside of your own account.
    
![Explorers up and running with serverless functions GitHub repo - Use this template button](https://cdn.sanity.io/images/o0o2tn5x/production/6c938686e66266a03a6c44f6861652c946494128-2570x970.png?w=450)
    
- Give your cloned repo a name and click the **Create repository from template** button.
    
![Create repository from template button](https://cdn.sanity.io/images/o0o2tn5x/production/6a2eb6d9900334f1a176eca52e08ec91f35804b7-1770x1428.png?w=450)
    
- Once you have created the new repository, click the **Code** button and copy the link to clone the repository.
    
![Copy button to grab repo url to clone](https://cdn.sanity.io/images/o0o2tn5x/production/3cdfa9f8af774c845a8737c3640f712841173d04-2234x1078.png?w=450)
    

### Setting up the Project Locally

- Open up a terminal to the location you want the project to be placed at, then run the `git clone` command and paste your link that you copied in the last step.
    
    ```bash
    git clone https://github.com/brittneypostma/new-cloned-serverless-functions-repo
    ```
    
- You can change directory with `cd` into your new project folder directly from the terminal or open your folder in your favorite code editor.
    
    ```bash
    cd new-cloned-serverless-functions-repo
    ```
    
- Currently there is only a `[README.md](http://README.md)` and `.gitignore` file and a `public` folder inside.

### Netlify CLI

Now that you have the [project cloned](#project-setup) and up [setup locally](#setting-up-the-project-locally), we need to install the packages needed to run the serverless functions locally. First, make sure you have [Node.js](https://nodejs.org/en/) installed on your machine. You can check if you have it and what version by running `npm --version`. Now, we need to install the Netlify Command Line Interface, or CLI. Run the following command in the terminal to install it globally on your machine.

```bash
npm install netlify-cli --global
```

You can either use the `netlify` or the shorthand `ntl` to run cli commands. I’ll be using the shorthand versions for the remainder of the tutorial. Check the version you are running of the cli with `ntl --version`.

If you don’t already have a Netlify account, you can [sign up for free here](https://app.netlify.com/signup). Then you can login with the CLI by running `ntl login` and authorize the application.

![Authorize Application for Netlify CLI](https://cdn.sanity.io/images/o0o2tn5x/production/e9725fdf09d55d495e3cb6edaae763ebf61147d5-1085x322.png?w=450)
Now we need to initialize the application by running `ntl init` and go through the steps to create a new site on Netlify.

1. Run `ntl init` and select `Create & configure a new site.`
    
![Create and configure a new site](https://cdn.sanity.io/images/o0o2tn5x/production/26c31abef2bcf5919ebb75303ffdcdf1daafc6fe-1660x374.png?w=450)
    
2. Select the team you want to use.
    
![Team: Brittney Postma's team](https://cdn.sanity.io/images/o0o2tn5x/production/2bd693b55a9b8cbdc351f2f0a68bd5c8290af3f3-528x142.png?w=450)
    
3. Name your site or leave it blank for a random name.
    
![site name (optional)](https://cdn.sanity.io/images/o0o2tn5x/production/1d8282cbc0c06f551b266797ebbaa99d5d775ed8-1428x86.png?w=450)
    
4. The site is now created. You should see your admin URL, the main URL, and the site id listed in the terminal.
    
![Site Created, list of URLs and site id](https://cdn.sanity.io/images/o0o2tn5x/production/71fcc6bc21186a02ef4761adeb2a6ac4b78127f6-1762x308.png?w=450)
    
5. The CLI will prompt us for the build command, leave this blank and the CLI will fill in `# no build command`.
    
![Your build command (hugo build/yarn run build/etc): # no build command](https://cdn.sanity.io/images/o0o2tn5x/production/2cfaef97e903f5ba5dc47031f2c6f333907c1619-1422x68.png?w=450)
    
6. Fill in the directory to deploy as the `public` folder.
    
![Directory to deploy (blank for current)](https://cdn.sanity.io/images/o0o2tn5x/production/501aee66078f05c853de6b70685224557dd18ed1-1068x72.png?w=450)
    
7. In this step, leave the default `netlify/functions` folder.
    
![Netlify functions folder: netlify/functions](https://cdn.sanity.io/images/o0o2tn5x/production/130a6d6331b335df252b965600f331032ad435c4-914x72.png?w=450)
    
8. And since we haven’t created a `netlify.toml` file yet, in this step, enter `Y` to generate one with the settings you specified.
    
![No netlify.toml detected. Would you like to create one with these build settings? Y](https://cdn.sanity.io/images/o0o2tn5x/production/4254a6a620df12f0f511e938c02febc9368b698c-1702x72.png?w=450)
    
9. Once you see the Success! message, your site is ready to deploy. There are some next steps listed, `git push` to trigger a deploy or run `ntl open` to open your new site’s dashboard.
    
![Success! Netlify CI/CD Configurred! Next steps for deploying.](https://cdn.sanity.io/images/o0o2tn5x/production/501678863fd45603b970178f82b1f1480fb017d6-1718x466.png?w=450)

## Anatomy of a Serverless Function

The basic anatomy of any serverless function has three basic parts. It must export a handler asynchronous function and then return an object with a `statusCode` and `body` property, which typically has a JSON object that needs to be converted to a string using the `JSON.stringify()` method for the `message` to be read.

```jsx
export const handler = async () => {
	return {
		statusCode: 200,
		body: JSON.stringify({
			message: 'This is what will be returned!'
		})
	}
}
```

## Project Overview

Now that the [project is set up locally](#project-setup) and [linked to a Netlify url](#netlify-cli), we can start looking through the project. 

### index.html

Open up the directory you created in your favorite code editor and navigate inside the public directory to the `index.html` file and open it up.

![new-cloned-serverless-functions-repo with list of files](https://cdn.sanity.io/images/o0o2tn5x/production/f2a78f83fdbfe4556a97c0942f6be62891e01c64-606x328.png?w=450)

If you look inside the `<body>` tag, you should see an `<h1>` tag, a `<button>` with an `id="fetch-btn"`, and a `<p>` placeholder for the response. In the `<script>` tag below, there is an event listener that listens for a click on the button and inserts the response into the placeholder area.

### netlify.toml

The next file to look at is the `netlify.toml` file that we setup with the [Netlify CLI](#netlify-cli). The build settings should be set up as follows.

```toml

[build]
	command = "# no build command"
	functions = "netlify/functions"
	publish = "public"

[functions]
        node_bundler = "esbuild"

```

The directory for the functions defined in the toml file hasn’t been created yet. At the root of your project, create a new folder named netlify and another folder inside it named functions. The new project structure should look like this.

![netlify.toml file highlighted in list of files](https://cdn.sanity.io/images/o0o2tn5x/production/42a1a66c65f02e66b05740f418405ff5f6e64077-278x282.png?w=450)

## Creating Your First Serverless Function

Inside of the new `netlify/functions` directory, create a new file `hello-world.js`. Use the `export` syntax and create an async function called `handler`, that returns a `statusCode` of 200 and a `body` with the `message` that is stringified with the `JSON.stringify` method.

```jsx
export const handler = async () => {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Hello World!',
    }),
  }
}
```

### Fetching the Response

Now, let’s configure the client side JavaScript we will use to fetch the response over in the `index.html` file. In the `script` tag below the markup, there is a `fetchBtn` event listener set up to listen for a click on the button in the markup. Here we need to make the function `async`, create a variable to fetch the serverless function endpoint, and return the response. One interesting thing to point out, is when we fetch the serverless function, we need to call it at the directory `.netlify`, with a dot in front of it. This is to avoid name collisions with other APIs.

```jsx
fetchBtn.addEventListener('click', async () => {
  const response = await fetch('/.netlify/functions/hello-world')
		.then(response => response.json()
	)

  responseText.innerText = response
})
```

Once the function is setup, we can run `ntl dev` in the console to run the development server and test the function. Open up `[localhost:8888](http://localhost:8888)` in the browser, open the developer console, and navigate to the network panel.

![Network panel showing in dev tools in Chrome browser with page running above](https://cdn.sanity.io/images/o0o2tn5x/production/760f24c5816436a0c13fc7edd521bfa742dd072e-1216x1218.png?w=450)

When you click on the fetch button, you will see the `hello-world` call come into the network panel.

![Network request for hello-world](https://cdn.sanity.io/images/o0o2tn5x/production/2b6c79333856ef618bf5d74320081247c6080955-1290x700.png?w=450)

You can see the `200` status and if you click on the function and navigate to the Preview tab, you can see the object message of “Hello World!”.

![Preview panel with message: "Hello World!"](https://cdn.sanity.io/images/o0o2tn5x/production/9f6c3cd393c54a2066e61b85c2d261ab5e658ef7-1022x690.png?w=450)

You may notice the text is printing `[object Object]`, this is because we need to stringify the response in the `fetchBtn` event listener function. Add the `JSON.stringify(response)` method and save the file.

```jsx
fetchBtn.addEventListener('click', async () => {
  const response = await fetch('/.netlify/functions/hello-world')
		.then(response => response.json()
	)

  responseText.innerText = JSON.stringify(response)
})
```

If you reload the site and click the Fetch button again, now the message will display correctly.

!["message": "Hello World!" displaying on page in browser](https://cdn.sanity.io/images/o0o2tn5x/production/d93d4c2f5a4b81a13e228a2c20e3eabab20b682c-1206x282.png?w=450)

## Calling an API from a Serverless Function

External APIs can be integrated with a serverless function to grab data, that can then be used in the response. We are going to work with the [Poke API](https://pokeapi.co/), which allows you to get all kinds of information about the Pokémon world.

### Creating a New Endpoint

Back in the code editor, we need to create a new file in our `netlify/functions` directory named `pokedex.js` that will house our new endpoint. This time, create a constant for the `POKE_API` url `https://pokeapi.co/api/v2/pokedex/kanto`, await the fetch call to the url, and create a new constant, `data`, and await the `response.json()`. Next, we’ll return the `statusCode: 200,` and stringify the data response in the body.

```jsx
export const handler = async () => {
  const POKE_API = 'https://pokeapi.co/api/v2/pokedex/kanto'

  const response = await fetch(POKE_API)
  const data = await response.json()

  return {
    statusCode: 200,
    body: JSON.stringify({
      data
    })
  }
}
```

### Fetch the Pokédex Endpoint

Back in the `index.html` file, first we will need to add a new button to fetch the [`pokedex.js` endpoint we just created](#creating-a-new-endpoint). Add a new button to the markup, with the id `fetch-pokedex-btn` and the text Fetch Pokedex.

```html
<button id="fetch-pokedex-btn">Fetch Pokedex</button>
```

![button with id of fetch-pokedex-btn highlighted](https://cdn.sanity.io/images/o0o2tn5x/production/1b7e99fcfed7f6b821b4a421b47e5938ec240f2e-1012x304.png?w=450)

Next in the `script` tag, create a constant and add the element selector.

```jsx
const fetchPokedexBtn = document.getElementById('fetch-pokedex-btn')
```

![fetchPokedexBtn variable line highlighted](https://cdn.sanity.io/images/o0o2tn5x/production/803f2c2571adeada58336c8324116bb56ca80fc8-1304x262.png?w=450)

And finally, create a new event listener function for a click on the `fetch-pokedex-btn` to add the stringified data to the `innerText` of the variable set to the `p` tag.

```jsx
fetchPokedexBtn.addEventListener('click', async () => {
	const response = await fetch('/.netlify/functions/pokedex')
		.then(response => response.json())

  responseText.innerText = JSON.stringify(response)
})
```

![fetchPokedexBtn event listener highlighted](https://cdn.sanity.io/images/o0o2tn5x/production/d51720150193c55eaa5e079aaf1a7965838fb863-1248x360.png?w=450)

At this point, if you run the server with `ntl dev`, you will see both of the buttons we created, but the Fetch Pokedex button will return an error. Checking the network panel and the terminal for the issue, we’ll see a 500 error and an `errorMessage: "fetch is not defined"`.

![dev tools 500 error on the network panel](https://cdn.sanity.io/images/o0o2tn5x/production/77ebfa9f3eb52a9841590e3802c472d4916e674b-1658x702.png?w=450)

![terminal error with errorMessage fetch is not defined.](https://cdn.sanity.io/images/o0o2tn5x/production/92d8ebaa27bcbde57cddbdb19eeb028cf4ecfdea-1596x176.png?w=450)

This happens because the serverless function running at the `pokedex.js` endpoint is on a [Node.JS](https://nodejs.org/en/) server. Node does not have access to the native fetch API provided inside the browser. As a result, we need to install a dependency that will allow us to run fetch on a Node server. Shut down the server with `ctrl+C` and follow the next steps to set up server-side fetch.

### Initializing NPM

To install packages inside of our application, we need to create initialize this as a `npm` project. To do that, run `npm init` in the root directory of your project. This will walk through steps to create a `package.json` file. You can leave everything as default by hitting `Enter` through each step or change anything by typing it in and then hitting `Enter`. Once complete, it will ask you “Is this OK?” and you hit `Enter` for yes or type no if you wish to start over.

![the npm init printout with Is this OK? (yes) at the bottom](https://cdn.sanity.io/images/o0o2tn5x/production/7b1c15af2848f830849cce674c6889eaa508bb45-1808x1162.png?w=450)

Once you say yes and hit `Enter`, a new `package.json` file will be created at the root of your project with the above information. 

![package.json file highlighted in list of files](https://cdn.sanity.io/images/o0o2tn5x/production/431b28defebd89c15ed9bc4cb3433ec8ada04324-280x418.png?w=450)

This file is responsible for keeping track of any dependencies and some basic details of the project. 

### ESM Support in Node

As of [Node.js](https://nodejs.org/en/) version `17.0.0`, ESM, or ECMAScript modules, support became available in any Node.js application. Some libraries, like the one we will be installing next, have made the ESM migration. While you can use libraries with or without ESM, you can’t pick and choose the syntax you use. You must completely convert your application to ESM or stick with the old syntax. The [original videos this tutorial is based on](https://explorers.netlify.com/learn/up-and-running-with-serverless-functions) used the older syntax for the serverless functions. We have since updated the [repo](https://github.com/netlify/explorers-up-and-running-with-serverless-functions) and this guide is using the newer ESM supported syntax. To convert over to ESM, add a `"type": "module"` to the `package.json` file and switch the `exports.handler = async function ()` to `const handler = async () =>`. If you have any imports using the `require()` syntax, they will also need to be converted to `import name from 'package'` syntax.


Replace the CommonJS syntax:
```js
const fetch = require('node-fetch')

exports.handler = async function () {
```

with the ESM syntax:
```js
import fetch from 'node-fetch'

export const handler = async () => {
```

We also need to update the `netlify.toml` file to tell Netlify to use `esbuild` for the serverless functions when they are deployed. Add the setting `node_bundler = "esbuild"` under `[functions]`

```jsx
[functions]
  node_bundler = "esbuild"
```

![toml file with functions setting](https://cdn.sanity.io/images/o0o2tn5x/production/2dee5b40cc86da947b322872f9c3caf96d26d0f4-594x320.png?w=450)

### Installing Packages

Now that we have the [`package.json` file created](#initializing-npm), we can install a Node fetch library. In the terminal, run the command `npm install --save-dev node-fetch`. Once it is completed, you will see a new `devDependencies` property with the `node-fetch` library in the `package.json` file and a new `package-lock.json` file created automatically. 

![package.json showing node-fetch as a dev dependency](https://cdn.sanity.io/images/o0o2tn5x/production/e8f11717d5cbdbf7891bc1335cc2adfea377584e-1388x274.png?w=450)

Your version will probably look different than mine. If you run into any issues, try removing `node-fetch` with the `npm rm node-fetch` command and then install `npm install --save-dev node-fetch@3.2.8` to install the save version.

### Import Packages

Head back to the `netlify/functions/pokedex.js` file where we need to import and use the [`node-fetch` library we just installed](#installing-packages). We’ll need to use the `import` syntax, since version 3 and greater of the `node-fetch` library uses ESM syntax. Add this line to the beginning of the file.

```jsx
import fetch from 'node-fetch
```

Don’t forget, you also have to update the `package.json` file with a `"type": "module"` property if you didn’t already to tell it to use ESM as well.

Now if you start the server again with `ntl dev` and navigate to `[localhost:8888](http://localhost:8888)` in the browser, you can see the function run successfully.

## Deploying Serverless Functions

Earlier [we setup and linked a site to Netlify with the Netlify CLI](#netlify-cli). Any time we make a *push* to the git repository that is linked to the Netlify site, a deploy will automatically trigger. Let’s go ahead and run the commands to push our code and trigger a deploy.

1. Shut down your server, if it isn’t already, with `Ctrl+C`.
2. Add all of the files with the `git add .` command, I have 7 changes to commit. 
    
![7 staged changes in files](https://cdn.sanity.io/images/o0o2tn5x/production/f159ca53b40e96fe446a52227655e215167a057e-444x418.png?w=450)

3. Commit the files with a message about what was changed.
    
    ```jsx
    git commit -m 'Set up a Netlify site with 2 serverless functions.'
    ```
    
4. Push the changes up to your git provider with `git push` or `git push origin main`.

That *push* will have set off a deployment on [Netlify](https://app.netlify.com). You can run `ntl open` to open the Netlify dashboard linked to your site. Once there, you can click directly on the [url](https://brittney-explorers-intro-to-serverless-functions.netlify.app/) to open the site or click on the **Deploys** tab to see the last deployment log.

![Deploys tab highlighted in nav](https://cdn.sanity.io/images/o0o2tn5x/production/d7ce90447a9b47585a842564c9be94603437b803-792x628.png?w=450)

To see the serverless functions we created, click on the **Functions** tab.

![Functions tab highlighted in nav](https://cdn.sanity.io/images/o0o2tn5x/production/e77e1d2fe01b8bbdb0743fc5e1c35b8fe8e7a505-792x628.png?w=450)

You should then see the 2 functions listed by the name of the files.

![Function tab with hello-world and pokedex functions listed](https://cdn.sanity.io/images/o0o2tn5x/production/c3c956f1bf9b9e495f68f996570855d645147333-878x964.png?w=450)

You can further click into each function to see the times and logs from when they were ran.

## Customizing the Serverless Functions Request

Any serverless function can *do stuff* to the data before it returns to the frontend. It can be customized in whatever way you need it and only return the things you want to use. In our example the `pokedex.js` is returning all of the data about every Pokémon and wasting space on information we probably don’t need. Back in the `pokedex.js` file in your code editor, customize the `data` object being returned in the `body` to limit it to only the `pokemon_entries`.

```jsx
import fetch from 'node-fetch'

export const handler = async () => {
  const POKE_API = 'https://pokeapi.co/api/v2/pokedex/kanto'

  const response = await fetch(POKE_API)
  const data = await response.json()

  return {
    statusCode: 200,
    body: JSON.stringify({
      pokemon: data.pokemon_entries
    })
  }
}
```

This will limit what is returned to just a list of the Pokémon without some of the extra data. 

### Fetching Different Data

Back in the `index.html` file, we’ll add another button and update our current one to grab 2 different types of data. Update the button with the id `fetch-pokedex-btn` to the id `fetch-kanto-btn`. Then add a new button with an id of `feetch-hoenn-btn`.

```html
<button id="fetch-kanto-btn">Fetch Kanto Pokedex</button>
<button id="fetch-hoenn-btn">Fetch Hoenn Pokedex</button>
```

We’ll also need to update the variables and functions in the script tag. Replace the `fetchPokedexBtn` line with the new variables that grab the new ids.

```jsx
const fetchKantoBtn = document.getElementById('fetch-kanto-btn')
const fetchHoennBtn = document.getElementById('fetch-hoenn-btn')
```

Next, we have to update the event listener functions to grab the different data types. First, update the name on the current `fetchPokedexBtn` event listener to be `fetchKantoBtn`. Now we can edit the data coming back by using the native fetch API, which takes an options object as a second parameter, to pass a `POST` method and send the custom data back to the serverless function. Here we want to specify the kanto region for the Pokémon API.

```jsx
fetchKantoBtn.addEventListener('click', async () => {
	const response = await fetch('/.netlify/functions/pokedex', {
		method: 'POST',
		body: JSON.stringify({
			region: 'kanto'
		})
	})
		.then(response => response.json())

	responseText.innerText = JSON.stringify(response)
})fetchKantoBtn.addEventListener('click', async () => {
	const response = await fetch('/.netlify/functions/pokedex', {
		method: 'POST',
		body: JSON.stringify({
			region: 'kanto'
		})
	})
		.then(response => response.json())

	responseText.innerText = JSON.stringify(response)
})
```

We also need an event listener function for the “Fetch Hoenn Pokedex” button. We’ll do the same thing, but switch out the `kanto` region for `hoenn`.

```jsx
fetchHoennBtn.addEventListener('click', async () => {
	const response = await fetch('/.netlify/functions/pokedex', {
		method: 'POST',
		body: JSON.stringify({
			region: 'hoenn'
		})
	})
		.then(response => response.json())

	responseText.innerText = JSON.stringify(response)
})
```

### Event and Context Parameters

All serverless functions accept two parameters, `event` and `context`. The `event` object includes information about the request and the `context` parameter includes information about the context that the function was called in. We can use the `event` object to grab the custom headers we are sending along with the requests we added to our `index.html` code. In the `pokedex.js` file, add the two parameters to the handler function and log the event and context with `console.log(event, context)` I like to wrap the variables I am logging in an object, `{}`, to see the name when it comes through. 

```jsx
// pokedex.js
import fetch from 'node-fetch'

export const handler = async (event, context) => {
  console.log({event}, {context})
  const POKE_API = 'https://pokeapi.co/api/v2/pokedex/kanto'

  const response = await fetch(POKE_API)
  const data = await response.json()

  return {
    statusCode: 200,
    body: JSON.stringify({
      pokemon: data.pokemon_entries
    })
  }
}
```

Save the file and run `ntl dev`, click on one of the Fetch Kanto Pokedex button and in the terminal you will see a lot of data coming back. The important part here is the `event.body`, which you will see is the region of the Pokémon that we sent through the `POST` method. 

![body region kanto printout](https://cdn.sanity.io/images/o0o2tn5x/production/54e9d4d5faf75ec56e793bf1a7a09f6ac8f957fd-580x72.png?w=450)

We are going to use this information by creating a variable to hold the parsed `event.body` and then update the url that is fetched to dynamically update depending on the region sent.

```jsx
import fetch from 'node-fetch'

export const handler = async (event, context) => {
  const eventBody = JSON.parse(event.body)
  const POKE_API = 'https://pokeapi.co/api/v2/pokedex/kanto' + eventBody.region

  const response = await fetch(POKE_API)
  const data = await response.json()

  return {
    statusCode: 200,
    body: JSON.stringify({
      pokemon: data.pokemon_entries
    })
  }
}
```

Now if you refresh the page and click the two Pokedex buttons, you will see two separate sets of data based on the region specified. You can *add*, *commit*, and *push* your code to git to kick off a [new deploy of the site](https://brittney-explorers-intro-to-serverless-functions.netlify.app/).

## Next Steps with Serverless Functions

Great job! You have experienced how serverless functions can give developers superpowers to build and customize functionality in their applications. This allows you to solve business needs with a wider range of tools and techniques without needing to manage any infrastructure. Now there’s a whole realm of possibilities for you to explore with serverless functions. To learn more about how you can get the most out of serverless functions with Netlify be sure to [check out the official docs](https://docs.netlify.com/functions/build-with-javascript/) where you can learn more about other solutions, such as [background functions](https://docs.netlify.com/functions/build-with-javascript/), which allow you to execute longer running scripts, using serverless techniques. I can't wait to see what you build with Netlify functions. Remember, if your experience is different from anything written here or something didn’t work as expected, please [let us know about it here](https://answers.netlify.com/) and we will help you or answer any questions you have.