Step by Step Guide: Migrating v3 to v4 programming model for Azure Functions for Node.Js Application

This post has been republished via RSS; it originally appeared at: Microsoft Tech Community - Latest Blogs - .

Welcome!

 

Hi, Developers! Today I would like to teach you how we can migrate to version 4 of the Node.js programming model for Azure Functions, using a real case project: Contoso Real Estate.

 

1. What is Azure Functions v4 for Node?

 

Hi, friends! Are you curious about Azure Functions v4 for Node? Let me tell you all about it! 8)

Azure Functions v4 is the latest version of the Node.js programming model for Azure Functions. It comes with a bunch of new features and improvements, such as:

 

  • Flexible folder structure
  • Being able to define function.json directly in the function's in the code
  • New HTTP trigger types
  • Improved IntelliSense
  • Timer Trigger (TypeScript)
  • Durable Functions (TypeScript)

Migrating from v3 to v4 is necessary to take advantage of these new features and improvements as well as the new features of latest versions of the Node.js runtime. However, it's important to note that v4 is still in preview. It is not yet recommended for production use and should be tested for correct behavior in development environments.

Learn more:

2. Migrate an existing Azure Functions v4 app

 

Microsoft offers a comprehensive guide to help migrate from v3 to v4 complete with tips and best practices to help you with the migration process, covering topics like:

 

  • Some important considerations
  • Requirements to make the migration
  • How to enable the v4 programming model
  • How to 
    • Include the npm package
    • And set up the app entry point
  • How to define the function in code
  • The new usage of context
  • Review the usage of HTTP types

Let's take dive in and see that process with a real app! Let's try this with our Contoso Real Estate Reference Sample

 

3. About Contoso Real Estate Reference App

 

The Contoso Real Estate Reference App is a sample application that demonstrates how to build a real estate website using Azure services in a composable architecture fashion. The app is constructed using a variety of technologies, including TypeScript, Node.js, and the frameworks Angular, Next.js and payment technologies like Stripe. The app includes features such as property listings, property details, and property search. The app also includes an admin portal for managing properties and users.

 

We then use a selected set of Azure serverless services to deploy to and run the app. Azure Functions plays a key role in the Contoso Real Estate Reference App by providing the backend APIs. The app uses an OpenAPI spec to define the API, and Azure Functions are used to implement the API endpoints. One benefit of using Azure Functions for the API is that it provides fully managed serverless capabilties, which means that you only pay for the compute resources that you use. One challenge of using Azure Functions for the API is that you need to ensure that your functions are secure and scalable.

Learn more:

 

 

4. Let's Migrate The App to Azure Functions v4.

 

1 | :backhand_index_pointing_right: Identify the target function(s)

 

For this article, we will migrate only one function from the Contoso Real Estate API to version 4, as it would not be possible to migrate all of them in a single article. The project has has several functions like this -- if you want to see the whole migration process end-to-end, bookmark and watch my Contoso Real Estate API YouTube playlist.

 

  • This has a series of 10 videos that cover migration of all functions
  • The videos are in Portuguese but should give you a frame of reference to follow along.

The function migration we will be covering in this article is get-users

 

Screen-Shot-08-07-23-at-07-41-PM.png

 

note: I made 10 videos (in Portuguese) explaining how I did the entire project API. If you want to watch, just access the playlist: Contoso Real Estate API.

 

2 | :backhand_index_pointing_right: Create a new branch in project

Let's use Codespaces! Since it comes with the default development environment pre-defined, it is easier and faster to jumpstart our development without having to set things up ourselves.

 

note: Codespaces offers free 60 hours per month, renewed on a monthly basis. Whenever you stop using the resource, you must turn off Codespaces to avoid unwanted consumption.

I created a development environment for this migration using Codespaces and consequently created a new branch called GL/content-v3-to-v4. If you want to do the same, feel free. And now inside the packages folder create a folder called api-v4.

Let's go to the steps to migrate the function.

 

  1. To follow this migration, I will be using the Visual Studio Code extension: Azure Functions. This extension allows us to create an Azure Functions project quickly and easily. To do this, just click on the Azure Functions icon in the Visual Studio Code sidebar and click the Create New Project button.

  2. Then click on: Browse and select the api-v4 folder that we created earlier.

  3. Choose the option: TypeScript

  4. Choose the option: Model V4 (Preview)

  5. Choose the option: HTTP trigger and consequently name the trigger: users

If you want to follow the step by step, just see the gif below:

 

v4-function-users.gif

 

 

3 | :backhand_index_pointing_right: Create a new folder for v4 refactor

Once you have created the project, note in the api-v4 folder the new folder structure of the new Node.js programming model for Azure Functions.

 

glaucia_lemos86_0-1691763912807.png

 

Notice that we now have a folder called src and inside it we have a folder called functions and inside it we have the file users.ts. This file is our HTTP trigger that we created earlier.

 

Much less 'polluted' than version 3, isn't it? In which each function had its own folder and inside it had the index.ts file and the function.json.

 

Did you notice another detail? The function.json file no longer exists. Now, we can define using app.http or app.get within our code.

 

  • src/functions/index.ts
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";

export async function users(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    context.log(`Http function processed request for url "${request.url}"`);

    const name = request.query.get('name') || await request.text() || 'world';

    return { body: `Hello, ${name}!` };
};

app.http('users', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: users
});
 

Also note the package.json file:

  • package.json
{
  "name": "api-v4",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "clean": "rimraf dist",
    "prestart": "npm run clean && npm run build",
    "start": "func start",
    "test": "echo \"No tests yet...\""
  },
  "dependencies": {
    "@azure/functions": "^4.0.0-alpha.7"
  },
  "devDependencies": {
    "@types/node": "^18.x",
    "typescript": "^4.0.0",
    "rimraf": "^5.0.0"
  },
  "main": "dist/src/functions/*.js"
}

 

Please, note that the @azure/functions package is in version 4.0.0-alpha.7. This is because version 4 is still in preview. And, as we are using TypeScript, there is a property called main that points to the *.js file inside the dist/src/functions folder. Later we will make a small change to this file.

 

To test and see if the function is working, just run the command: npm start, Codespaces will ask you to open the browser. At the end of the URL put: /api/users. If the phrase: Hello World appears, it is because it is working correctly.

 

See the step by step in the gif below:

 

execution-function-v4.gif

 

4 | :backhand_index_pointing_right: Migration `get-users` (v3 function) to `users` (v4)

note: the Contoso Real Estate project API makes use of Azure Cosmos DB. If you don't know, I recommend that you read the documentation. It is a globally distributed, multi-model, NoSQL database and multi-API. In this case here, the MongoDB API is being used and consequently the ORM Mongoose. Let's assume that you have already copied the files related to the database for your migration of the new version of the Azure Functions programming model and that we are only now migrating the functions, okay?

Now that we have the project structure, let's migrate the get-users (v3) function to users (v4). Open the users.ts file and let's start the migration.

 

  • src/functions/users.ts
import { HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
import { findUsers } from "../models/user";

// GET: All users
export async function getUsers(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
  context.log(`Http function getUsers processed request for url "${request.url}"`);

  const offset = Number(request.query.get("offset")) || 0;
  const limit = Number(request.query.get("limit")) || 10;

  if (offset < 0) {
    return {
      status: 400,
      jsonBody: {
        error: "Offset must be greater than or equal to 0",
      },
    };
  } else if (limit < 0) {
    return {
      status: 400,
      jsonBody: {
        error: "Limit must be greater than or equal to 0",
      },
    };
  } else if (offset > limit) {
    return {
      status: 400,
      jsonBody: {
        error: "Offset must be less than or equal to limit",
      },
    };
  }

  try {
    const users = await findUsers({ offset, limit });

    if (users) {
      return {
        jsonBody: users,
      };
    } else {
      return {
        status: 404,
        jsonBody: {
          error: "Users not found",
        },
      };
    }
  } catch (error) {
    return {
      status: 500,
      jsonBody: {
        error: "Internal Server Error",
      },
    };
  }
};

app.http('users', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  handler: getUsers
});

 

Probably you will see an error in app.http, because I intentionally removed the call from app at the beginning of the file. Now comes a small change. To make the project more organized, let's create a file inside the src folder called: index.ts. This file will be responsible for importing all the functions of the project and exporting to the main of package.json.

 

Remove the app.http block contained in the users.ts file and paste it into the index.ts file. Then, import the getUsers function and export it.

 

  • src/functions/users.ts
app.http('users', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  handler: getUsers
});

  

  • src/index.ts
import { app } from "@azure/functions";
import { getUsers } from "./functions/users";

app.get('get-users', {
  route: 'users',
  authLevel: 'anonymous',
  handler: getUsers
});

 

Notice that, instead of using app.http, we use app.get. This is because, this method specifically will be handling the HTTP verb GET.

In the new Azure Functions programming model, the HTTP verbs are:

 

  • app.get
  • app.post
  • app.put
  • app.patch
  • app.deleteRequest

And, finally go to the package.json file and change the main property to: dist/src/index.js.

 

If you want to create a POST, for example, just use the app.post method and so on. And, there in the users.ts file just include the logic related to the HTTP verb POST.

 

What does this mean? The project structure will be more: concise, simple and very similar to what is already used in Express.js.

 

Now let's run the project! Run the command: npm start and open the browser. At the end of the URL put: /api/users. In this case, as I am not with the database, it will return an error. But, if you have the database, it will return the registered users or according to the API you will be using.

 

final-execution-v4.gif

 

Conclusion

Congratulations! We just migrated a v3 Azure Functions app to the new v4 Functions programming model for Node.js, in a few simple steps.

 

Let's summarize what we learned today:

 

  • the key differences between Azure Functions v3 and v4 programming models for Node.js
  • how to create a new Azure Functions v4 app from scratch
  • the new model is simpler and more concise (no need for a file per function!)

The specific file changes for this migration can be found in this Pull Request on the Contoso Real Estate application repository. Browse it to get an understanding of the design decisions made and challenges faced when trying to migration a complex project at scale!

 


Contributions Welcome

And, feel free to make contributions to the project. There is a list of good first issues that you can contribute to.

I hope you enjoyed it and see you next time!

 

 

Leave a Reply

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

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.