Visual Studio Codespaces を使って Azure Functions の Java アプリケーションの Hello World まで

# 背景

`Visual Studio Codespaces` が登場して、VDIのマシンを立てずとも、`Azure` 上の仮想マシンを使ってのコーディングがやり易くなりました。しかも `Windows`と`Linux`が選択できます。`Visual Studio Code` との連携がシームレス過ぎて感動さえ覚えます。

Visual Studio Codespaces:
https://visualstudio.microsoft.com/ja/services/visual-studio-codespaces/

Visual Studio Codespaces - document:
https://docs.microsoft.com/ja-jp/visualstudio/online/overview/what-is-vsonline

- 執筆時点 (2020/6/5) は **Public Preview** です!

一方、`Azure Functions` は Serverless で人気のホスティング環境です。

Azure Functions:
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-overview

その実行エンジンはGitHub上で開発されており、オンプレミスだけでなく、AWS や GCP、あるいは k8s 上などあらゆる環境にホスティングして動かす事ができます。

https://github.com/Azure/azure-functions-host

ここでは、それらを使っての Java アプリケーションの Hello World までの手順をまとめておきます。
ローカルに Java でさえインストールしていない点にご注意ください😊

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/0c840831-2d0f-c03f-7fe5-cff203a24f83.png)


# 必要なもの

- ローカルに
    - Visual Studio Code
    
    https://code.visualstudio.com/


    - Visual Studio Code Remote Development Extension Pack

    https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack

- Azure Subscription


# 手順

## 1. Visual Studio Codespaces の環境作成

こちらのドキュメントに従って作成してください😊

Visual Studio Codespaces Quickstart:
https://docs.microsoft.com/ja-jp/visualstudio/online/quickstarts/browser

**数十秒で作成**されます! 
Container ベースであることも読み取れて興味深いですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/b08ea5f5-cb95-734f-ae0d-e4f4af0f896f.png)

## 2. Visual Studio Codespaces に Visual Studio Code から接続

Visual Studio Codespaces はデフォルトでブラウザー内での作業になることが多いです。ですが、私は**ローカル**でのコーディングが好きなので😁、ここからはローカルの Visual Studio Code で作業をしていきます。

- Visual Studio Codespaces のサイトに移動します

https://online.visualstudio.com/

- 作成したインスタンスを選んで [Open in VS Code] を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/7c2dad30-aa0f-d555-cb34-84e824c3e125.png)

- ブラウザーから、Visual Studio Code を開こうとしているというメッセージが出てきます。[開く]で先に進みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/e27e2e05-ee52-8cd6-186a-4879c725176f.png)

こんな形で、リモートに接続ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/769be30b-0c36-058e-0108-baf77a1fea09.png)

- もし認証がうまくできないなどで、接続がうまくいかない場合は、画面左下の緑の[Codespace: <インスタンス名>]をクリックして、[Codespaces: Open Codespace in New Window]にて、別のVisual Studio Codeを起動してみてください.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/1aa04d36-3dae-d80c-975c-a09bfd4a31eb.png)

## 3. 開発に必要なモジュールを Visual Studio Codespaces にインストール

開発に必要な幾つかのモジュールが入っていません。**ターミナル** から、それらをインストールします。

- Visual Studio Code でターミナルを開きます
実際にはリモートのContainerに接続しているんですよね😊

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/fd013e93-965f-9202-ba3a-6dc9dd0a356f.png)

## 3.1. Maven

```bash
sudo apt-get install maven
```

## 3.2. Azure Functions Core Tools 

Visual Studio Codespaces 上で Azure Functions を実行するためですね。リモートでのローカル実行になります😎

```bash
sudo apt-get install azure-functions-core-tools
```

Azure Functions Core Tools の操作:
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-run-local?tabs=linux%2Ccsharp%2Cbash

## 3.3. Azure Functions - Visual Studio Code Extension
Visual Studio Code の Extension です。Visual Studio Codespaces の方にインストールします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/38e0659d-8dfc-5881-9ad6-92ef72acda7a.png)

これで、Visual Studio Code のアクティビティバーに Azure のアイコンが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/72b7600e-fd7c-9209-f478-4656513feeda.png)

## 3.4. Java Extension Pack - Visual Studio Code Extension
Visual Studio Code の Java 用の各種 Extension です。デバッグのためですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/8c9cbe5b-6b42-40fc-5c88-808990179cf9.png)

これで、ほぼ既存の Azure Functions のドキュメントの手順の通り作業ができます😊

## 4. Azure Functions のローカルプロジェクトの作成

手順はこちらですね。

https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-create-first-function-vs-code?pivots=programming-language-java#create-your-local-project

ちなみに、以下の様なJavaのコードのひな型を作成してくれます。

/src/main/java/com/function/Function.java

```java
package com.function;

import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;

import java.util.Optional;

/**
 * Azure Functions with HTTP Trigger.
 */
public class Function {
    /**
     * This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash:
     * 1. curl -d "HTTP Body" {your host}/api/HttpExample
     * 2. curl "{your host}/api/HttpExample?name=HTTP%20Query"
     */
    @FunctionName("HttpExample")
    public HttpResponseMessage run(
            @HttpTrigger(
                name = "req",
                methods = {HttpMethod.GET, HttpMethod.POST},
                authLevel = AuthorizationLevel.ANONYMOUS)
                HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");

        // Parse query parameter
        final String query = request.getQueryParameters().get("name");
        final String name = request.getBody().orElse(query);

        if (name == null) {
            return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
        } else {
            return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
        }
    }
}
```


## 5. Visual Studio Codespace 上で、Azure Functions のコードをデバッグする

ドキュメントの通りですと、F5 でローカルでAzure Functionsが起動します。ここでは、Visual Studio Codespace 側、つまり、リモートで起動させます。

- [ターミナル] を起動して、以下のコマンドを発行します。

```bash
mvn clean package
```

結構時間かかります😅...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/e5d80140-457d-006a-2e0b-29c4d5445f59.png)


```bash
mvn azure-functions:run
```

で、見慣れた Azure Functions の実行画面に。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/a718535f-6cb8-6703-2a18-8b31fa0feb3e.png)

これで、Visual Studio Codespaces 上で、Azure Functions が起動しました!

ちなみに、debug実行する際には以下のコマンドになります。
ブレークポイントが動いていませんが...😅

```bash
mvn azure-functions:run -DenableDebug
```

## 6. Visual Studio Codespace 上の Azure Functions にアクセスする

Azure Functions Core Tools がデフォルトで作成してくれる アクセス用のURLである http://localhost:7071/api/HttpExample は、自分のPCからそのままではアクセスできませんよね。

Visual Studio Codespaceのインスタンス上の Azure Functionsに接続するため、ここでは、Visual Studio Code の Remote Extensionに入っているポートフォワーディングを利用します。

- アクティビティーバーの [リモートエクスプローラー] を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/5063d043-b98c-8f93-611b-3c5eb7bf620e.png)

- [Forward port...] を選択し、ローカルでのポート番号を入れます。Azure Functions Core Tools が設定してくれたポート番号である**[7071]**を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/1ec95bc5-e069-1f30-d059-61cb3e991b90.png)

- 作成した Forward Ports を選択すると、URLをコピーするアイコンが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/58cb5614-54f0-8ade-d744-28e666fb4740.png)

この文字列がクリップボードにコピーされます。

```bash
http://127.0.0.1:7072/
```

そのままブラウザーのURLに張り付けてコピーすると、Azure Functions が稼働していることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/87694fa6-7560-3a8e-9cca-3745b08310a6.png)

このサンプルは、Visual Studio Codespaces 側では以下のURLで待っています。

```bash
http://localhost:7071/api/HttpExample
```

これを以下の様に書き換えます。
QueryStringの name の先はどんな文字列でも良いです😊

```bash
http://127.0.0.1:7072/api/HttpExample?name=Hello-VisualStudioCodespace
```

Azure Functions が呼び出せましたね!

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/e8c22509-118f-cf69-79fc-9a1cd37f7c39.png)

# まとめ
Visual Studio Codespaces が、Azure上の**リモート環境**という事を忘れなければ、普段の開発に近い形で行えると思います。

- Container の 作成・削除は容易
- 追加モジュールもインストール可能
- アイドル時間設定で、勝手に止めてくれる

是非、楽しんでください!

## 参考

Visual Studio Codespaces VS Code How-to:
https://docs.microsoft.com/ja-jp/visualstudio/online/how-to/vscode

Maven Plugin for Azure Functions:
https://docs.microsoft.com/ja-jp/java/api/overview/azure/maven/azure-functions-maven-plugin/readme?view=azure-java-stable#azure-functionsrun

Azure Functions の Java 開発者向けガイド:
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-java?tabs=consumption


Visual Studio Code での Remote 環境での開発:
https://code.visualstudio.com/docs/remote/remote-overview