연습 - 함수 앱에 논리 추가

완료됨

기어 드라이브 예제를 계속 사용하여 온도 서비스에 대한 논리를 추가해 보겠습니다. 특히 HTTP 요청에서 데이터를 수신하겠습니다.

함수 요구 사항

먼저 논리에 대한 몇 가지 요구 사항을 정의해야 합니다.

  • 0~25도 사이의 온도는 OK로 플래그를 지정해야 합니다.
  • 25~50도 사이의 온도는 CAUTION으로 플래그를 지정해야 합니다.
  • 50도가 넘는 온도는 DANGER로 플래그를 지정해야 합니다.

함수 앱에 함수 추가

이전 단원에서 설명한 바와 같이, Azure는 함수 빌드에 도움이 되는 템플릿을 제공합니다. 이 단원에서는 HttpTrigger 템플릿을 사용하여 온도 서비스를 구현합니다.

  1. 이전 연습에서는 함수 앱을 배포하고 열었습니다. 아직 열지 않은 경우 홈페이지에서 모든 리소스를 선택한 다음, escalator-functions-xxx와 같은 이름의 함수 앱을 선택하여 열 수 있습니다.

  2. 함수 앱 화면의 함수 탭 아래에서 Azure Portal에서 만들기를 선택합니다. 함수 만들기 창이 나타납니다.

  3. 템플릿 선택에서 HTTP 트리거를 선택합니다.

  1. 만들기를 선택합니다. HttpTrigger1이 만들어지고 HttpTrigger1 함수 창에 표시됩니다.

  2. 왼쪽의 개발자 메뉴에서 코드 + 테스트를 선택합니다. 코드 편집기가 열리고 함수에 대한 index.js 코드 파일의 콘텐츠가 표시됩니다. HTTP 템플릿이 생성한 기본 코드가 다음 코드 조각에 표시됩니다.

    module.exports = async function (context, req) {
        context.log('JavaScript HTTP trigger function processed a request.');
    
        const name = (req.query.name || (req.body && req.body.name));
        const responseMessage = name
            ? "Hello, " + name + ". This HTTP triggered function executed successfully."
            : "This HTTP triggered function executed successfully. Pass a name on the query string or in the request body for a personalized response.";
    
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: responseMessage
        };
    }
    

    함수는 HTTP 요청 쿼리 문자열을 통해 또는 요청 본문의 일부로서 이름이 전달될 것이라고 예상합니다. 이 함수는 Hello, <name>. This HTTP triggered function executed successfully. 메시지를 반환하고, 요청에서 보낸 name을 다시 에코하여 응답합니다.

    원본 드롭다운 목록에서 function.json을 선택하여 함수의 구성을 보면 다음 코드와 유사합니다.

    {
      "bindings": [
        {
          "authLevel": "function",
          "type": "httpTrigger",
          "direction": "in",
          "name": "req",
          "methods": [
            "get",
            "post"
          ]
        },
        {
          "type": "http",
          "direction": "out",
          "name": "res"
        }
      ]
    }
    

    이 구성 파일은 HTTP 요청을 수신할 때 함수가 실행되도록 선언합니다. 출력 바인딩은 응답이 HTTP 응답으로 전송됨을 선언합니다.

  1. 템플릿 세부 정보 섹션의 새 함수 필드에 DriveGearTemperatureService를 입력합니다. 권한 부여 수준을 "함수"로 유지한 다음, 만들기를 선택하여 함수를 만듭니다. DriveGearTemperatureService 함수의 개요 창이 나타납니다.

  2. 함수 메뉴에서 코드 + 테스트를 선택합니다. run.ps1 코드 파일의 내용과 함께 코드 편집기가 열립니다. 템플릿이 생성한 기본 코드가 다음 코드 조각에 나열되어 있습니다.

    using namespace System.Net
    
    # Input bindings are passed in via param block.
    param($Request, $TriggerMetadata)
    
    # Write to the Azure Functions log stream.
    Write-Host "PowerShell HTTP trigger function processed a request."
    
    # Interact with query parameters or the body of the request.
    $name = $Request.Query.Name
    if (-not $name) {
        $name = $Request.Body.Name
    }
    
    $body = "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
    
    if ($name) {
        $body = "Hello, $name. This HTTP triggered function executed successfully."
    }
    
    # Associate values to output bindings by calling 'Push-OutputBinding'.
    Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
        StatusCode = [HttpStatusCode]::OK
        Body = $body
    })
    

    함수는 HTTP 요청 쿼리 문자열을 통해 또는 요청 본문의 일부로서 이름이 전달될 것이라고 예상합니다. HTTP 함수는 Push-OutputBinding cmdlet을 사용하여 PowerShell Functions에서 수행되는 출력 바인딩에 기록하여 응답을 생성해야 합니다. 이 함수는 Hello $name 메시지를 반환하고, 요청에서 보낸 이름을 다시 에코합니다.

  3. 원본 드롭다운 목록에서 function.json을 선택하여 함수의 구성을 보면 다음과 같습니다.

    {
      "bindings": [
        {
          "authLevel": "function",
          "type": "httpTrigger",
          "direction": "in",
          "name": "Request",
          "methods": [
            "get",
            "post"
          ]
        },
        {
          "type": "http",
          "direction": "out",
          "name": "Response"
        }
      ]
    }
    

    이 구성은 HTTP 요청을 수신할 때 함수가 실행되도록 합니다. 출력 바인딩은 응답이 HTTP 응답으로 전송됨을 선언합니다.

함수 테스트

cURL은 파일을 보내거나 받는 데 사용할 수 있는 명령줄 도구입니다. Linux, macOS 및 Windows 10에 포함되어 있으며 대부분의 다른 운영 체제에 다운로드할 수 있습니다. cURL은 HTTP, HTTPS, FTP, FTPS, SFTP, LDAP, TELNET, SMTP, POP3 등과 같은 많은 프로토콜을 지원합니다. 자세한 내용은 다음 링크를 참조하십시오.

함수를 테스트하려면 명령줄에서 cURL을 사용하는 함수 URL에 HTTP 요청을 전송할 수 있습니다.

  1. 트리거 함수 창 하단에 있는 로그 프레임을 확장합니다. Logs 프레임 위쪽의 드롭다운에서 파일 시스템 로그를 선택합니다. 로그 프레임은 1분마다 추적 알림 발생을 시작해야 합니다.

  2. 함수의 엔드포인트 URL을 찾으려면 다음 이미지와 같이 명령 모음에서 함수 URL 받기를 선택합니다. URL의 끝에 있는 클립보드로 복사 아이콘을 선택하여 이 링크를 저장합니다. 나중에 사용할 수 있도록 이 링크를 메모장과 같은 앱에 저장합니다.

    Screenshot of the Azure portal showing the function editor, with the Get function URL button highlighted.

  3. 명령 프롬프트를 열고 cURL 실행하여 함수 URL에 HTTP 요청을 보냅니다. 이전 단계에서 복사한 URL을 사용하세요.

    curl "<your-https-url>"
    

    URL의 특수 문자와 관련된 문제를 방지하기 위해 URL을 따옴표로 래핑할 수 있습니다.
    Windows를 사용하는 경우 명령 프롬프트에서 cURL을 실행합니다. PowerShell에는 curl 명령이 있지만 이 명령은 Invoke-WebRequest에 대한 별칭이며 cURL과 동일하지 않습니다.

    응답은 다음과 같은 모습이어야 합니다.

    This HTTP triggered function executed successfully. Pass a name on the query string or in the request body for a personalized response.
    

    이제 요청으로 이름을 전달합니다. 이를 위해서는 이름이 name인 쿼리 문자열 매개 변수를 URL에 추가해야 합니다. 다음은 쿼리 문자열 매개 변수 name=Azure을 추가하는 예제입니다.

    curl "<your-https-url>&name=Azure"
    

    응답은 다음과 같은 모습이어야 합니다.

    Hello, Azure. This HTTP triggered function executed successfully.
    

    함수가 성공적으로 실행되어 요청에서 전달한 이름이 반환되었습니다.

HTTP 트리거 보호

HTTP 트리거를 사용하면 API 키를 사용하여 요청의 일부로 키가 필요하도록 설정하여 알 수 없는 호출자를 차단할 수 있습니다. 함수를 만들 때 권한 부여 수준을 선택합니다. 기본값으로 함수로 설정되며 함수별 API 키가 필요합니다. 글로벌 “마스터” 키를 사용하는 관리자 또는 키 사용이 필요 없음을 나타내기 위해 익명으로 설정할 수도 있습니다. 생성 후에 함수 속성을 통해 권한 부여 수준을 변경할 수도 있습니다.

이 함수를 만들 때 함수를 지정했으므로 HTTP 요청을 보낼 때 키를 제공해야 합니다. code라는 쿼리 문자열 매개 변수로 보낼 수 있습니다. 또는 기본 설정하는 방법을 사용하고 이를 x-functions-key라는 HTTP 헤더로 전달합니다.

  1. 함수 및 마스터 키를 찾으려면 Function App 메뉴의 개발자 아래에서 함수 키를 선택합니다. 함수에 대한 함수 키 창이 열립니다.

  2. 기본적으로 함수 키 값은 숨겨져 있습니다. 값 표시를 선택하여 기본 함수 키 값을 표시합니다. 필드의 콘텐츠를 클립보드에 복사한 다음 나중에 사용할 수 있도록 이 키를 메모장이나 유사한 앱에 저장합니다.

    Screenshot showing the Function Keys pane with the revealed function key highlighted.

  3. 함수 키를 사용하여 함수를 테스트하려면 명령 프롬프트를 열고 cURL 실행하여 함수 URL에 HTTP 요청을 보냅니다. <your-function-key>를 저장한 함수 키 값으로 바꾸고 <your-https-url>을 함수의 URL로 바꿉니다.

    curl --header "Content-Type: application/json" --header "x-functions-key: <your-function-key>" --request POST --data "{\"name\": \"Azure Function\"}" <your-https-url>
    
  4. cURL 명령을 검토하고 다음 값이 있는지 확인합니다.

    • application/json 형식의 Content-Type 헤더 값을 추가했습니다.
    • 함수 키를 헤더 값 x-functions-key로 전달했습니다.
    • POST 요청을 사용했습니다.
    • 함수에 대한 URL과 함께 Azure 함수를 전달했습니다.
  5. 로그를 확인합니다.

    코드 + 테스트 창에서 로그 파일 출력을 표시하는 세션이 열려야 합니다. 로그창의 맨 위에 있는 드롭다운에서 파일 시스템 로그가 선택되어 있는지 확인하세요. 로그 파일은 요청의 상태로 업데이트되며, 다음과 유사하게 표시됩니다.

```output
2022-02-16T22:34:10.473 [Information] Executing 'Functions.HttpTrigger1' (Reason='This function was programmatically called via the host APIs.', Id=4f503b35-b944-455e-ba02-5205f9e8b47a)
2022-02-16T22:34:10.539 [Information] JavaScript HTTP trigger function processed a request.
2022-02-16T22:34:10.562 [Information] Executed 'Functions.HttpTrigger1' (Succeeded, Id=4f503b35-b944-455e-ba02-5205f9e8b47a, Duration=114ms)
```
```output
2022-02-16T21:07:11.340 [Information] INFORMATION: PowerShell HTTP trigger function processed a request.
2022-02-16T21:07:11.449 [Information] Executed 'Functions.DriveGearTemperatureService' (Succeeded, Id=25e2edc3-542f-4629-a152-cf9ed99680d8, Duration=1164ms)
```

함수에 비즈니스 논리 추가

함수에 논리를 추가하여 수신하는 온도 값을 확인하고 각 온도 값에 대한 상태를 설정해 보겠습니다.

만든 함수는 다양한 온도 값을 수신할 것으로 예상됩니다. 다음 JSON 코드 조각은 함수에 전송할 요청 본문의 예입니다. 각 reading 항목에는 ID, 타임스탬프 및 온도가 있습니다.

{
    "readings": [
        {
            "driveGearId": 1,
            "timestamp": 1534263995,
            "temperature": 23
        },
        {
            "driveGearId": 3,
            "timestamp": 1534264048,
            "temperature": 45
        },
        {
            "driveGearId": 18,
            "timestamp": 1534264050,
            "temperature": 55
        }
    ]
}

비즈니스 논리를 구현하기 위해 함수의 기본 코드를 다음 코드로 바꾸겠습니다.

HttpTrigger1 함수 창에서 index.js 파일을 열고 다음 코드로 바꿉니다. 이렇게 변경한 후 명령 모음에서 저장을 선택하여 파일에 업데이트 사항을 저장합니다.

module.exports = function (context, req) {
    context.log('Drive Gear Temperature Service triggered');
    if (req.body && req.body.readings) {
        req.body.readings.forEach(function(reading) {

            if(reading.temperature<=25) {
                reading.status = 'OK';
            } else if (reading.temperature<=50) {
                reading.status = 'CAUTION';
            } else {
                reading.status = 'DANGER'
            }
            context.log('Reading is ' + reading.status);
        });

        context.res = {
            // status: 200, /* Defaults to 200 */
            body: {
                "readings": req.body.readings
            }
        };
    }
    else {
        context.res = {
            status: 400,
            body: "Please send an array of readings in the request body"
        };
    }
    context.done();
};

추가한 논리는 간단합니다. 배열을 반복하고 온도 필드의 값에 따라 상태를 OK, CAUTION의 또는 DANGER로 설정합니다. 그런 다음, 각 항목에 추가된 상태 필드와 함께 값의 배열을 다시 전송합니다.

창의 하단에 있는 로그를 확장하면 Log 문이 표시됩니다. 함수가 실행되면 이러한 문은 로그 창에 메시지를 추가합니다.

run.ps1 파일을 열고 콘텐츠를 다음 코드로 바꿉니다. 이렇게 변경한 후 명령 모음에서 저장을 선택하여 파일에 업데이트 사항을 저장합니다.

using namespace System.Net

param($Request, $TriggerMetadata)

Write-Host "Drive Gear Temperature Service triggered"

$readings = $Request.Body.Readings
if ($readings) {
    foreach ($reading in $readings) {
        if ($reading.temperature -le 25) {
            $reading.Status = "OK"
        }
        elseif ($reading.temperature -le 50) {
            $reading.Status = "CAUTION"
        }
        else {
            $reading.Status = "DANGER"
        }

        Write-Host "Reading is $($reading.Status)"
    }

    $status = [HttpStatusCode]::OK
    $body = $readings
}
else {
    $status = [HttpStatusCode]::BadRequest
    $body = "Please send an array of readings in the request body"
}

Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = $status
    Body = $body
})

추가한 논리는 간단합니다. 배열을 반복하고 온도 필드의 값에 따라 상태를 OK, CAUTION의 또는 DANGER로 설정합니다. 그런 다음, 각 항목에 추가된 상태 필드와 함께 값의 배열을 다시 전송합니다.

Write-Host에 대한 호출을 확인합니다. 함수가 실행되면 이러한 문은 로그 창에 메시지를 추가합니다.

비즈니스 논리 테스트

개발자>코드 + 테스트에서 테스트/실행 기능을 사용하여 함수를 테스트하겠습니다.

  1. 입력 탭에서 본문 텍스트 상자의 내용을 다음 코드로 바꾸어 샘플 요청을 만듭니다.

    {
        "readings": [
            {
                "driveGearId": 1,
                "timestamp": 1534263995,
                "temperature": 23
            },
            {
                "driveGearId": 3,
                "timestamp": 1534264048,
                "temperature": 45
            },
            {
                "driveGearId": 18,
                "timestamp": 1534264050,
                "temperature": 55
            }
        ]
    }
    
  2. 실행을 선택합니다. 출력 탭에는 HTTP 응답 코드 및 콘텐츠가 표시됩니다. 로그 메시지를 보려면 창의 맨 아래 플라이아웃에서 로그 탭을 엽니다(열려 있지 않은 경우). 다음 이미지에서는 출력 창의 예제 응답 및 로그 창의 메시지를 보여 줍니다.

    Screenshot of the Azure function editor, with the Test and Logs tabs showing.

    출력 탭에서 상태 필드가 각 값에 올바르게 추가되었음을 확인할 수 있습니다.

  3. 요청이 Application Insights에 기록되었는지 확인하려면 왼쪽의 개발자 메뉴에서 모니터를 선택합니다. 함수에 대한 모니터 창이 나타납니다.

    창의 호출 탭에는 각 함수 호출에 대한 호출 추적이 표시됩니다. 호출 중 하나에 대해 날짜(UTC) 값을 선택하고 함수 실행에 대한 세부 정보를 봅니다.