Build a Nuxt app with Azure serverless REST API
Tags: serverless, typescript, azure, nuxt
Published: 2024-03-12 10:57:45

---
title: "Build a Nuxt app with Azure serverless REST API"
description: "Learn how to add serverless APIs to a Nuxt app using Azure Functions and its tools."
tags: ['serverless', 'TypeScript', 'Azure', 'Nuxtjs' ]
published: true
cover_image: https://res.cloudinary.com/mayashavin/image/upload/v1710240615/articles/azure/azure_serverless_nuxt.png
series: Developing Serverless Web Apps
canonical_url: https://mayashavin.com/articles/azure-serverless-function-nuxt
---

_In this article, we will learn how to build an static web app using Nuxt, with serverless APIs using Azure Functions CLI and Static Web Apps Emulator._

## Table of Content

- [Table of Content](#table-of-content)
- [Prerequisites](#prerequisites)
- [Setting up API project with Azure Function Core Tools](#setting-up-api-project-with-azure-function-core-tools)
- [Adding an serverless API for products](#adding-an-serverless-api-for-products)
  - [Implementing the `getProducts` function](#implementing-the-getproducts-function)
  - [Registering the `getProducts` function](#registering-the-getproducts-function)
- [Fetching products from API on the client-side](#fetching-products-from-api-on-the-client-side)
- [Run and debug locally](#run-and-debug-locally)
  - [Installing Azure Static Web App CLI](#installing-azure-static-web-app-cli)
  - [Running the app locally with swa emulator](#running-the-app-locally-with-swa-emulator)
- [Resources](#resources)
- [Summary](#summary)

## Prerequisites

For our demo app, we will use Nuxt project with Vite. However, feel free to use any other frontend framework per your preference.

We create our demo app `azure-funcs-demo-nuxt` with the following command:

```bash
npx nuxi@latest init azure-funcs-demo-nuxt
```

And since we will build and deploy our APIs with Azure functions, you need an active Azure subscription ([a free subscription is also available](https://azure.microsoft.com/en-in/free/)).

Lastly, you need to have [Node.js v20+](https://nodejs.org/en/download/) and [Azure Function Core Tools CLI](https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=macos%2Cisolated-process%2Cnode-v4%2Cpython-v2%2Chttp-trigger%2Ccontainer-apps&pivots=programming-language-javascript#install-the-azure-functions-core-tools) installed for setting up our APIs project, which we will cover in the next section.

## Setting up API project with Azure Function Core Tools

Azure Functions Core Tools is a set of CLI tools that you can use to create, develop, debug, and deploy Azure Functions in different programming languages.

Within our project's directory, we will create an TypeScript `api` project, using the below command:

```bash
func init api --worker-runtime typescript --model V4
```

The CLI then generates a new `api` folder, containing the following main files and folders:

- `.funcignore` - contains the list of files and folders to be ignored when deploying to Azure.
- `host.json` - metadata file contains global configurations for all functions.
- `local.settings.json` - contains app settings, connection strings, environment variables used by local development tools.
- `package.json` - contains list of dependencies and scripts for the project.
- `tsconfig.json` - contains the TypeScript configurations.
- `src/functions` - where the function code resides.

We can now create a new function. Let's do it next.

## Adding an serverless API for products

For our store, we create a serverless API function `getProducts` that returns a list of products, upon an HTTP GET request. To do so, within our `/api` folder, we run the below command:

```bash
func new --name getProducts --template "HTTP trigger"
```

Note here we use `HTTP trigger` as the template for serverless function.

The above command will create a new file `src/functions/getProducts.ts`, with some boilerplate code. We will go through and adjust the code to our needs.

### Implementing the `getProducts` function

The boilerplate code defines a trigger function `getProducts` that accepts two arguments:

- `request` - the actual request details.
- `context` - for logging, binding data, and retrieving other context information.

This function returns a `Promise<HttpResponse>` including the response's data, which is currently a simple string in the `body`.

We re-implement `getProducts` to return a list of products and an OK status code (`200`), as seen in the below code:

```typescript
export async function getProducts(
    request: HttpRequest, 
    context: InvocationContext
): Promise<HttpResponseInit> {
  const products = [
    { id: 1, name: 'Product 1', price: 100 },
    { id: 2, name: 'Product 2', price: 200 },
    { id: 3, name: 'Product 3', price: 300 },
  ];

  return { jsonBody: products, status: 200 };
};
```

Note here we replace the `body` with `jsonBody` to return the products as a JSON object. Otherwise, the response will be returned as a string.

Next, we will modify the function registration to handle only GET requests, and to be available at the endpoint `api/products`.

### Registering the `getProducts` function

Azure CLI registered our `getProducts` function with a default configuration using `app.http()`, located at the end of the `getProducts.ts` file as follows:

```js
/**... */
app.http('getProducts', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: getProducts
});
```

The above code registers the `getProducts` function as the handler for an HTTP request to the endpoint `api/getProducts`, with the following configurations' properties:

- `methods` - the list of HTTP methods that the API supports.
- `authLevel` - the authentication level to access the API, such as `anonymous`.
- `handler` - the function handles the API request, which is `getProducts`.
- `route` - the route template of the API endpoint. This params is very handy when we need a dynamic route for the API, while keeping the registered function name consistently.

To have the API available as `api/products` and only accept 'GET' requests, we change `methods` to 'GET', and its registered name to be `products` instead, as below:

```js
app.http('products', {
  methods: ['GET'],
  authLevel: 'anonymous',
  handler: getProducts
});
```

We can also use the `route` property to achieve the same result, as follows:

```typescript
app.http('getProducts', {
  //...
  methods: ['GET'],
  route: 'products'
});
```

Our API is now ready for us to consume in our web app, which we will do next.

## Fetching products from API on the client-side

In our main codebase, we will create a `pages/products.vue` page that fetches the products from the API `api/products`, with the help of Nuxt's `useFetch()`, as seen below:

```html
<template>
  <h1>Products</h1>
  <div v-if="pending">
    Loading ...
  </div>
  <ul v-else>
    <li v-for="product in products" :key="product.id">
      <article>
        <h2>{{ product.name }}</h2>
        <p>Price: {{ product.price }}</p>
      </article>
    </li>
  </ul>
</template>
<script setup>
const { data: products, pending } = await useFetch('/api/products', {
  server: false
});
</script>
```

That's it! Let's run and debug our app locally.

## Run and debug locally

To run the app locally and have both the frontend and the api proxy in the same domain, we will use [Azure Static Web App CLI](https://github.com/Azure/static-web-apps-cli).

### Installing Azure Static Web App CLI

We install the CLI globally with the following command:

```bash
npm install -g @azure/static-web-apps-cli
```

Once installed, within our project, we can run `swa` command and follow the prompts to configure the settings for running and deploying our app. The CLI then generates a `swa-cli.config.json` file containing the configurations, with the following crucial options:

- `apiLocation` - path to our APIs, which is `api`.
- `appLocation` - path to our web app, which is `.`.
- `outputLocation` - path to the build output of out web app, which is `dist`, mainly for deployment.
- `apiDevServerUrl` - the web app's local server, which is `http://localhost:3000` in our case.
- `run` - the command to run our web app locally, which is `yarn dev`.
- `apiDevserverUrl` - the API's local server, which is usually `http://localhost:7071`. Alternatively, you can manually set it using `--api-devserver-url` in the command line.
  
Next, we will run both our API and web app, and verify the integration between them.

### Running the app locally with swa emulator

First, in the `api` directory, we start the server for the APIs:

```bash
func start
```

The above command will run the server and provide us with the URL as seen below:

<img src="https://res.cloudinary.com/mayashavin/image/upload/f_auto,q_auto/v1675680195/articles/azure/api_server_local" loading="lazy" alt="The local server of API project" class="mx-auto"/>

Note that every time we modify the API code, we **must** restart the server to have the changes applied.

Next, in our main project's root directory, we start the proxy server for our app with the below command:

```bash
swa start
```

We will then have our web app's emulator running locally, with proxy to our APIs, at `http://localhost:4280`, as seen below:

<img src="https://res.cloudinary.com/mayashavin/image/upload/f_auto,q_auto/v1675680195/articles/azure/swa_web_app_api_server" loading="lazy" alt="Screenshot of the local server after running swa" class="mx-auto"/>

We can use this URL to access the web app using a browser. Both the API and the web app should be now running on the same server endpoint and accessible locally.

<img src="https://res.cloudinary.com/mayashavin/image/upload/f_auto,q_auto/v1675680195/articles/azure/nuxt_app_ui" loading="lazy" alt="Screenshot of the Nuxt app on running" class="mx-auto"/>

## Resources

The demo project is available on [GitHub](https://github.com/mayashavin/azure-funcs-demo-nuxt).

---

## Summary

In this post, we learned how to add a standard TypeScript serverless APIs project using Azure Functions. We also learned how to consume the created API in our Nuxt app and run both the API and the web app locally using SWA CLI Emulator. In the upcoming post, we will learn how to secure both API and the web app using OAuth2 Authentication, and deploy them to Azure.

👉 _Learn about Vue 3 and TypeScript with my new book [Learning Vue](https://www.oreilly.com/library/view/learning-vue/9781492098812/)!_

👉 _If you'd like to catch up with me sometimes, follow me on [X](https://x.com/MayaShavin) | [LinkedIn](https://www.linkedin.com/in/mayashavin)._

Like this post or find it helpful? Share it 👇🏼 😉