API TypeScript без сервера: хранение данных в MongoDB с помощью Функции Azure

Создайте API функций Azure для хранения данных с ПОМОЩЬЮ API Mongoose в Azure Cosmos DB, а затем разверните приложение-функцию в облаке Azure для размещения с общедоступной конечной точкой HTTP.

Примечание.

В этой статье используется модель программирования Функции Azure Node.js версии 4 в предварительной версии.

Flow chart showing path of HTTP request to pass data through Azure Functions and store in Azure Cosmos DB.

Подготовка среды разработки

Установите следующее программное обеспечение:

1. Вход в Azure в Visual Studio Code

Если вы уже используете расширения служб Azure, вы уже вошли в систему и можете пропустить этот шаг.

После установки расширения службы Azure в Visual Studio Code необходимо войти в учетную запись Azure.

  1. В Visual Studio Code откройте обозреватель Azure, выбрав значок Azure на основной боковой панели или используйте сочетание клавиш (SHIFT + ALT + A).

  2. В разделе "Ресурсы" выберите вход в Azure и следуйте инструкциям.

    Sign in to Azure through VS Code

  3. Выполнив вход, убедитесь, что адрес электронной почты вашей учетной записи Azure отображается в строке состояния, а ваши подписки — в Azure Explorer:

    VS Code Azure explorer showing subscriptions

2. Создание группы ресурсов Azure

Группа ресурсов представляет собой коллекцию ресурсов в определенном регионе. Создав группу ресурсов и ресурсы в этой группе, вы сможете в конце этого учебника удалить сразу всю группу ресурсов, а не каждый ресурс по отдельности.

  1. Создайте новую папку в локальной системе для использования в качестве корневого каталога проекта функций Azure.

  2. Откройте эту папку в Visual Studio Code.

  3. В Visual Studio Code откройте обозреватель Azure, выбрав значок Azure на основной боковой панели или используйте сочетание клавиш (SHIFT + ALT + A).

  4. Найдите подписку в разделе "Ресурсы" и щелкните + значок " Создать группу ресурсов".

  5. Для заполнения данных используйте значения из следующей таблицы.

    Prompt Значение
    Введите имя новой группы ресурсов. azure-tutorial
    Выберите расположение для новых ресурсов. Выберите ближайший к вам географический регион.

3. Создание локального приложения Функций

Создайте локальное приложение Функций Azure (бессерверных), которое содержит функцию триггера HTTP.

  1. В Visual Studio Code откройте палитру команд (CTRL SHIFT + + P).

  2. Найдите и выберите Функции Azure: создать проект.

  3. Чтобы завершить создание локального проекта функции Azure, примените данные из следующей таблицы.

    Prompt Значение Примечания.
    Выберите папку, содержащую проект функции Выберите текущую папку (по умолчанию).
    Выбор языка TypeScript
    Выбор модели программирования TypeScript Модель V4 (предварительная версия)
    Выбор шаблона для первой функции проекта Триггер HTTP API вызывается через HTTP-запрос.
    Provide a function name (Укажите имя функции) blogposts API использует маршрут /api/blogposts.
  4. Когда Visual Studio Code создает проект, просмотрите код API в ./src/functions/blogposts.ts файле.

    import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
    
    export async function blogposts(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('blogposts', {
        methods: ['GET', 'POST'],
        authLevel: 'anonymous',
        handler: blogposts
    });
    

    Этот код является стандартным шаблоном в новой модели программирования версии 4. Это не означает, что единственный способ записи слоя API с помощью POST и GET.

  5. Замените предыдущий код следующим кодом, чтобы разрешить только запросы GET возвращать все записи блога.

    import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
    
    // curl --location 'http://localhost:7071/api/blogposts' --verbose
    export async function getBlogPosts(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
        context.log(`Http function getBlogPosts processed request for url "${request.url}"`);
    
        // Empty array for now ... will fix later
        const blogposts = [];
    
        return {
            status: 200,
            jsonBody: {
                blogposts
            }
        };
    };
    
    app.get('getBlogPosts', {
        route: "blogposts",
        authLevel: 'anonymous',
        handler: getBlogPosts
    });
    

    Существует несколько Функции Azure изменения модели программирования Node.js версии 4 в этом коде, которые следует отметить:

    • Имя getBlobPostsфункции, указывающее, что это запрос GET, поможет изолировать функцию в журналах.
    • Для route свойства задано blogpostsзначение , которое является частью предоставленного /api/blogpostsмаршрута API по умолчанию.
    • methods Свойство было удалено и является ненужным, так как app использование get объекта указывает, что это запрос GET. Ниже перечислены функции метода. Если у вас другой метод, вы можете вернуться к использованию methods свойства.
      • deleteRequest()
      • get()
      • patch()
      • post()
      • put()

4. Запуск эмулятора локального хранилища Azurite

Для разработки функций на локальном компьютере требуется либо эмулятор служба хранилища (бесплатный), либо учетная запись служба хранилища Azure (платная).

В отдельном терминале запустите эмулятор локального хранилища Azurite .

azurite --silent --location ./azurite --debug ./azurite/debug.log

Это необходимо для локального запуска Функции Azure с помощью локального эмулятора служба хранилища Azure. Локальный эмулятор хранилища указан в local.settings.json файле со свойством AzureWebJobs служба хранилища со значениемUseDevelopmentStorage=true.

{
    "IsEncrypted": false,
    "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "AzureWebJobsFeatureFlags": "EnableWorkerIndexing"
    }
}

Вложенные azurite папки уже добавлены в .gitignore файл.

5. Запустите локальную бессерверную функцию

Локально выполните проект Функций Azure перед развертыванием в Azure.

  1. В Visual Studio Code установите точку останова в return инструкции в конце функции getBlogPosts .

  2. В Visual Studio Code нажмите клавишу F5, чтобы запустить отладчик и подключиться к узлу Функций Azure.

    Вы также можете использовать команду меню Debug (Отладка)>Start Debugging (Начать отладку).

  3. Выходные данные отображаются на панели терминала .

  4. В Visual Studio Code откройте обозреватель Azure, выбрав значок Azure на основной боковой панели или используйте сочетание клавиш (SHIFT + ALT + A).

  5. В разделе "Рабочая область" найдите и разверните локальный проект ->Functions ->getBlogPosts.

  6. Щелкните правой кнопкой мыши имя функции, getBlogPosts и выберите URL-адрес функции копирования.

    Partial screenshot of Visual Studio Code, with the Azure Function's button named Copy Function URL highlighted.

  7. В браузере вставьте URL-адрес и нажмите клавишу ВВОД или используйте следующую команду cURL в терминале:

    curl http://localhost:7071/api/blogposts --verbose
    

    Ответ пустого массива записей блога возвращается следующим образом:

    *   Trying 127.0.0.1:7071...
    * Connected to localhost (127.0.0.1) port 7071 (#0)
    > GET /api/blogposts HTTP/1.1
    > Host: localhost:7071
    > User-Agent: curl/7.88.1
    > Accept: */*
    >
    < HTTP/1.1 200 OK
    < Content-Type: application/json
    < Date: Mon, 08 May 2023 17:35:24 GMT
    < Server: Kestrel
    < Transfer-Encoding: chunked
    <
    {"blogposts":[]}* Connection #0 to host localhost left intact
    
  8. В VS Code остановите отладчик Shift + F5.

6. Создание приложения-функции Azure в Visual Studio Code

В этом разделе описано, как создать облачный ресурс приложения-функции и связанные ресурсы в подписке Azure.

  1. В Visual Studio Code откройте палитру команд (CTRL SHIFT + + P).

  2. Найдите и выберите Функции Azure: создание приложения-функции в Azure (дополнительно).

  3. Введите следующие сведения по соответствующим запросам:

    Prompt Выбор
    Ввод глобально уникального имени для приложения-функции Введите имя, допустимое в пути URL-адреса, например first-function. Поместите 3 символа, чтобы сделать URL-адрес глобально уникальным. Имя, которое вы вводите, проверяется, чтобы убедиться, что оно уникально в функциях Azure.
    Выберите стек сред выполнения Выберите Node.js 18 LTS или более раннюю версию.
    Выбор ОС Выберите Linux.
    Выбор группы ресурсов для новых ресурсов Создайте новую группу ресурсов с именем azure-tutorial-first-function. Эта группа ресурсов в конечном итоге будет иметь несколько ресурсов: Функция Azure, служба хранилища Azure и API Cosmos DB для MongoDB.
    Выбор плана размещения Выберите "Потребление".
    Выбрать учетную запись хранения Выберите "Создать учетную запись хранения" и примите имя по умолчанию.
    Выберите ресурс приложения Аналитика для приложения. Выберите "Создать приложение Аналитика" и примите имя по умолчанию.

    Подождите, пока уведомление не подтвердит, что приложение будет создано.

7. Развертывание приложения-функции Azure в Azure в Visual Studio Code

Важно!

Развертывание в существующем приложении-функции всегда перезаписывает содержимое этого приложения в Azure.

  1. Щелкните значок Azure на панели действий, а затем в области "Ресурсы " щелкните правой кнопкой мыши ресурс приложения-функции и выберите "Развернуть в приложении-функции".
  2. Если вам будет предложено развернуть, нажмите кнопку "Развернуть".
  3. После завершения развертывания появится уведомление с несколькими параметрами. Выберите "Просмотреть выходные данные ", чтобы просмотреть результаты. Если вы пропустили уведомление, щелкните значок колокольчика в правом нижнем углу, чтобы снова просмотреть его.

8. Добавление параметра приложения в облачное приложение

  1. Щелкните значок Azure на панели действий, а затем в области ресурсов разверните ресурс приложения-функции и щелкните правой кнопкой мыши пункт "Приложение Параметры".

  2. Выберите "Добавить новый параметр" и добавьте следующий параметр, чтобы включить модель программирования Node.js версии 4 (предварительная версия).

    Параметр Значение
    AzureWebJobsFeatureFlags EnableWorkerIndexing

9. Запустите удаленную бессерверную функцию

  1. В Visual Studio Code откройте обозреватель Azure, выбрав значок Azure на основной боковой панели или используйте сочетание клавиш (SHIFT + ALT + A).

  2. В разделе "Ресурсы" разверните ресурс приложения-функции Azure. Щелкните правой кнопкой мыши имя функции и выберите "Копировать URL-адрес функции".

  3. Вставьте URL-адрес в браузер. Тот же пустой массив возвращается, как при локальном запуске функции.

    {"blogposts":[]}
    

10. Добавление интеграции API Azure Cosmos DB для MongoDB

Azure Cosmos DB предоставляет API MongoDB для предоставления знакомой точки интеграции.

  1. В Visual Studio Code откройте обозреватель Azure, выбрав значок Azure на основной боковой панели или используйте сочетание клавиш (SHIFT + ALT + A).

  2. В разделе "Ресурсы" выберите + команду "Создать сервер базы данных". Чтобы завершить запрос на создание нового ресурса Azure Cosmos DB, используйте таблицу ниже.

    Prompt Значение Примечания.
    Выберите сервер базы данных Azure API Azure Cosmos DB для MongoDB
    Укажите имя учетной записи Azure Cosmos DB. cosmosdb-mongodb-database После добавления трех символов для создания уникального имени. Это имя станет частью URL-адреса API.
    Выберите модель емкости Бессерверные приложения
    Выберите группу ресурсов для новых ресурсов. azure-tutorial-first-function Выберите группу ресурсов, созданную в предыдущем разделе.
    Выберите расположение для новых ресурсов. Выберите рекомендуемый регион.

11. Установка монгоозной зависимости

В терминале Visual Studio Code ctrl + Shift + ` установите пакет npm:

npm install mongoose

12. Добавление кода mongoose для записей блога

  1. В Visual Studio Code создайте подкаталог с именем lib , ./src/создайте файл с именем ./database.ts и скопируйте в него следующий код.

    import { Schema, Document, createConnection, ConnectOptions, model, set } from 'mongoose';
    
    const connectionString = process.env.MONGODB_URI;
    console.log('connectionString', connectionString);
    
    const connection = createConnection(connectionString, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
      autoIndex: true
    } as ConnectOptions);
    
    export interface IBlogPost {
      author: string
      title: string
      body: string
    }
    
    export interface IBlogPostDocument extends IBlogPost, Document {
      id: string
      created: Date
    }
    
    const BlogPostSchema = new Schema({
      id: Schema.Types.ObjectId,
      author: String,
      title: String,
      body: String,
      created: {
        type: Date,
        default: Date.now
      }
    });
    
    BlogPostSchema.set('toJSON', {
      transform: function (doc, ret, options) {
          ret.id = ret._id;
          delete ret._id;
          delete ret.__v;
      }
    }); 
    
    export const BlogPost = model<IBlogPostDocument>('BlogPost', BlogPostSchema);
    
    connection.model('BlogPost', BlogPostSchema);
    
    export default connection;
    
  2. Откройте в Visual Studio Code файл ./src/functions/blogposts и замените весь код в этом файле следующим текстом:

    import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
    import connection from '../lib/database';
    
    // curl --location 'http://localhost:7071/api/blogposts' --verbose
    export async function getBlogPosts(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
        context.log(`Http function getBlogPosts processed request for url "${request.url}"`);
    
        const blogposts = await connection.model('BlogPost').find({});
    
        return {
            status: 200,
            jsonBody: {
                blogposts
            }
        };
    };
    
    app.get('getBlogPosts', {
        route: "blogposts",
        authLevel: 'anonymous',
        handler: getBlogPosts
    });
    

13. Добавление строка подключения в локальное приложение

  1. В обозревателе Azure Visual Studio Code выберите раздел Azure Cosmos DB и разверните его, чтобы щелкнуть правой кнопкой мыши новый ресурс.

  2. Выберите "Копировать строка подключения".

  3. В Visual Studio Code откройте проводник ./local.settings.json.

  4. Добавьте новое свойство с именем MONGODB_URI и вставьте значение строка подключения.

    {
      "IsEncrypted": false,
      "Values": {
        "AzureWebJobsStorage": "",
        "FUNCTIONS_WORKER_RUNTIME": "node",
        "AzureWebJobsFeatureFlags": "EnableWorkerIndexing",
        "MONGODB_URI": "mongodb://...."
      }
    }
    

    Секреты в ./local.settings.json файле:

    • Не развертывается в Azure, так как он включен в ./.funcignore файл.
    • Не проверка в систему управления версиями, так как он включен в ./.gitignore файл.
  5. Запустите приложение локально и протестируйте API с тем же URL-адресом в предыдущем разделе.

14. Добавление строка подключения в удаленное приложение

  1. В Visual Studio Code откройте обозреватель Azure, выбрав значок Azure на основной боковой панели или используйте сочетание клавиш (SHIFT + ALT + A).
  2. В разделе "Ресурсы" найдите экземпляр Azure Cosmos DB. Щелкните ресурс правой кнопкой мыши и выберите "Копировать строку Подключение ion".
  3. В том же разделе "Ресурсы" найдите приложение-функцию и разверните узел.
  4. Щелкните правой кнопкой мыши Параметры приложения и выберите Add New Setting (Добавить параметр).
  5. Введите имя MONGODB_URI параметра приложения и нажмите клавишу ВВОД.
  6. Вставьте скопированное значение и нажмите клавишу ВВОД.

15. Добавление API для создания, обновления и удаления записей блогов

  1. В Visual Studio Code используйте палитру команд, чтобы найти и выбрать Функции Azure: Создать функцию.

  2. Выберите триггер HTTP и назовите его blogpost (сингулярный).

  3. Скопируйте следующий код в файл.

    import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
    import connection, { IBlogPost, IBlogPostDocument }  from '../lib/database';
    
    // curl -X POST --location 'http://localhost:7071/api/blogpost' --header 'Content-Type: application/json' --data '{"author":"john","title":"my first post", "body":"learn serverless node.js"}' --verbose
    export async function addBlogPost(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
        context.log(`Http function addBlogPost processed request for url "${request.url}"`);
    
        const body = await request.json() as IBlogPost;
    
        const blogPostResult = await connection.model('BlogPost').create({
            author: body?.author,
            title: body?.title,
            body: body?.body
        });
    
        return {
            status: 200,
            jsonBody: {
                blogPostResult
            }
        };
    };
    
    // curl -X PUT --location 'http://localhost:7071/api/blogpost/64568e727f7d11e09eab473c' --header 'Content-Type: application/json' --data '{"author":"john jones","title":"my first serverless post", "body":"Learn serverless Node.js with Azure Functions"}' --verbose
    export async function updateBlogPost(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
        context.log(`Http function updateBlogPost processed request for url "${request.url}"`);
    
        const body = await request.json() as IBlogPost;
        const id = request.params.id;
    
        const blogPostResult = await connection.model('BlogPost').updateOne({ _id: id }, {
            author: body?.author,
            title: body?.title,
            body: body?.body
        });
    
        if(blogPostResult.matchedCount === 0) {
            return {
                status: 404,
                jsonBody: {
                    message: 'Blog post not found'
                }
            };
        }
    
        return {
            status: 200,
            jsonBody: {
                blogPostResult
            }
        };
    };
    
    // curl --location 'http://localhost:7071/api/blogpost/6456597918547e37d515bda3' --verbose
    export async function getBlogPost(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
        context.log(`Http function getBlogPosts processed request for url "${request.url}"`);
    
        console.log('request.params.id', request.params.id)
        const id = request.params.id;
    
        const blogPost = await connection.model('BlogPost').findOne({ _id: id });
    
        if(!blogPost) {
            return {
                status: 404,
                jsonBody: {
                    message: 'Blog post not found'
                }
            };
        }
    
        return {
            status: 200,
            jsonBody: {
                blogPost
            }
        };
    };
    
    // curl --location 'http://localhost:7071/api/blogpost/6456597918547e37d515bda3' --request DELETE --header 'Content-Type: application/json' --verbose
    export async function deleteBlogPost(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
        context.log(`Http function deleteBlogPost processed request for url "${request.url}"`);
    
        const id = request.params.id;
    
        const blogPostResult = await connection.model('BlogPost').deleteOne({ _id: id });
    
        if(blogPostResult.deletedCount === 0) {
            return {
                status: 404,
                jsonBody: {
                    message: 'Blog post not found'
                }
            };
        }
    
        return {
            status: 200,
            jsonBody: {
                blogPostResult
            }
        };
    };
    
    app.get('getBlogPost', {
        route: "blogpost/{id}",
        authLevel: 'anonymous',
        handler: getBlogPost
    });
    
    app.post('postBlogPost', {
        route: "blogpost",
        authLevel: 'anonymous',
        handler: addBlogPost
    });
    
    app.put('putBlogPost', {
        route: "blogpost/{id}",
        authLevel: 'anonymous',
        handler: updateBlogPost
    });
    
    app.deleteRequest('deleteBlogPost', {
        route: "blogpost/{id}",
        authLevel: 'anonymous',
        handler: deleteBlogPost
    });
    
  4. Снова запустите локальную функцию с отладчиком. Доступны следующие API:

    deleteBlogPost: [DELETE] http://localhost:7071/api/blogpost/{id}
    getBlogPost: [GET] http://localhost:7071/api/blogpost/{id}
    getBlogPosts: [GET] http://localhost:7071/api/blogposts
    postBlogPost: [POST] http://localhost:7071/api/blogpost
    putBlogPost: [PUT] http://localhost:7071/api/blogpost/{id}
    
  5. blogpost Используйте API (сингулярный) из команды cURL, чтобы добавить несколько записей блога.

    curl -X POST --location 'http://localhost:7071/api/blogpost' --header 'Content-Type: application/json' --data '{"author":"john","title":"my first post", "body":"learn serverless node.js"}' --verbose
    
  6. blogposts Используйте API (plural) из команды cURL, чтобы получить записи блога.

    curl http://localhost:7071/api/blogposts --verbose
    

16. Просмотр всех данных с расширением Visual Studio Code для Azure Cosmos DB

  1. В Visual Studio Code откройте обозреватель Azure, выбрав значок Azure на основной боковой панели или используйте сочетание клавиш (SHIFT + ALT + A).

  2. В разделе "Ресурсы" щелкните правой кнопкой мыши базу данных Azure Cosmos DB и выберите "Обновить".

  3. Разверните тестовую базу данных и узел коллекции blogposts, чтобы просмотреть документы.

  4. Выберите один из элементов, перечисленных для просмотра данных в экземпляре Azure Cosmos DB.

    Partial screenshot of Visual Studio Code, showing the Azure explorer with the Databases with a selected item displayed in the reading pane.

17. Повторно разверните приложение-функцию, чтобы включить код базы данных

  1. В Visual Studio Code откройте обозреватель Azure, выбрав значок Azure на основной боковой панели или используйте сочетание клавиш (SHIFT + ALT + A).
  2. В разделе "Ресурсы" щелкните правой кнопкой мыши приложение-функцию Azure и выберите "Развернуть в приложении-функции".
  3. Во всплывающем запустите всплывающее окно с запросом на развертывание, нажмите кнопку "Развернуть".
  4. Дождитесь завершения развертывания.

18. Использование облачной функции Azure

  1. По-прежнему в Обозреватель Azure в области "Функции" выбирает и расширяет функцию, а затем узел "Функции", в котором перечислены API-интерфейсы.
  2. Щелкните правой кнопкой мыши один из API и выберите URL-адрес функции копирования.
  3. Измените предыдущие команды cURL, чтобы использовать удаленный URL-адрес вместо локального URL-адреса. Выполните команды, чтобы проверить удаленный API.

19. Запрос журналов функций Azure

Для поиска по журналам используйте портал Azure.

  1. В Visual Studio Code выберите azure Обозреватель, а затем в разделе "Функции" щелкните правой кнопкой мыши приложение-функцию и выберите "Открыть на портале".

    Откроется страница портала Azure для Функции Azure.

  2. В Параметры выберите "Приложение Аналитика", а затем выберите "Просмотреть Аналитика данные приложения".

    Browser screenshot showing menu choices. Select **Application Insights** from the Settings, then select **View Application Insights data**.

    Эта ссылка позволяет перейти к отдельному ресурсу метрик, созданному вместе с функцией Azure в Visual Studio Code.

  3. В разделе "Мониторинг" выберите "Журналы". Если появится всплывающее окно Запросы, щелкните значок X в правом верхнем углу, чтобы закрыть его.

  4. В области New Query 1 на вкладке Таблицы дважды щелкните таблицу traces.

    Это действие помещает запрос Kustotraces в окно запроса.

  5. Измените этот запрос, чтобы выполнить поиск по пользовательским журналам:

    traces 
    | where message startswith "***"
    
  6. Выберите Выполнить.

    Если журнал не отображает результаты, это может быть связано с задержкой в нескольких минутах между HTTP-запросом к функции Azure и доступностью журнала в Kusto. Подождите несколько минут и выполните запрос еще раз.

    Для получения этих сведений из журнала не нужно предпринимать никаких дополнительных действий:

    • Код использовал функцию, предоставляемую context.log платформой функций. contextconsoleИспользуя вместо этого ведение журнала, можно отфильтровать для конкретной отдельной функции. Это полезно, если приложение-функция имеет множество функций.
    • Приложение-функция добавило Application Insights за вас.
    • Средство запроса Kusto входит в портал Azure.
    • Вы можете выбрать traces вместо того, чтобы научиться писать запрос Kusto, чтобы получить даже минимальную информацию из журналов.

20. Очистка ресурсов

Так как вы использовали одну группу ресурсов, все ресурсы можно удалить, удалив группу ресурсов.

  1. В Visual Studio Code откройте обозреватель Azure, выбрав значок Azure на основной боковой панели или используйте сочетание клавиш (SHIFT + ALT + A).
  2. Найдите и выберите Azure: группировать по группе ресурсов.
  3. Щелкните правой кнопкой мыши группу ресурсов и выберите команду "Удалить группу ресурсов".
  4. Введите имя группы ресурсов, чтобы подтвердить удаление.

Доступный исходный код

Полный исходный код для этого приложения-функции Azure:

Следующие шаги