LoginSignup
21
13

More than 5 years have passed since last update.

PowerShell製のWebフレームワーク、Polarisの使い方

Last updated at Posted at 2018-12-13

本記事は PowerShell Advent Calendar 2018 の 14 日目です。

100% PowerShellで書かれたPolarisというWebフレームワークの使い方を紹介します。

※Polarisは誕生してまだ1年あまりの試験的なプロジェクトのため、
 ここで記載した情報はすぐに古くなる可能性があります。(念のため)

Polarisとは

Polaris1とは、MicrosoftのPowerShellチームがOSSとして開発しているPowerShell製のWebフレームワークです。
100% PowerShell2で実装されており、Windows PowerShellとPowerShell Coreの両方で動作可能となっています。
現在、PoC(Proof of Concept)として開発されており、Microsoft製品としてはサポート対象外とされています。

項目 説明
開発元 Microsoft
登場時期 2017年10月3日(Initial commit)
最新版 0.2.0 / 2018年12月6日3
リポジトリ https://github.com/PowerShell/Polaris
プログラミング言語 PowerShell
対応OS Cross-platform (Windows, Linux or Mac)
ライセンス MIT License
公式ドキュメント https://powershell.github.io/Polaris/

特徴

サーバーの起動・停止はもとより、Web-APIリソースの追加、DocumentRootの指定などをすべてコマンドレットで行えることができます。
最近、「〇〇で爆速Webアプリ開発生活始めてみた!」のような記事が注目されています(偏見?)が
シンプルなGETのWeb-APIであれば、ワンラインで実装(もちろん、ホットデプロイ)できるので、
これ以上爆速があるのか?と思わせるくらい速い実装&実行が可能です。
ただ、サポートされる機能が非常にシンプルなため、一般的なWebアプリにはまだ使用することは現実的ではないと思っています。
Mockサーバーなど、手軽に利用したいものに関しては有効かもしれません。

環境構築

PolarisはPowerShell 5 以上が必要です。
PowerShellGetで取得できます。

Install-Module Polaris

使い方

以下、Polarisの基本形。

SampleServer.ps1
#Requires -Version 5.0
#Requires -Modules Polaris

$ErrorActionPreference = 'stop'

New-PolarisGetRoute -Path "/helloworld" -Force -Scriptblock {
    $Response.Send('Hello World!')
}
ターミナル(サーバー側)
PS> . .\SampleServer.ps1

PS> Start-Polaris
#=> Port              : 8080
#=> RouteMiddleWare   : {}
#=> ScriptblockRoutes : {[/helloworld, System.Collections.Generic.Dictionary`2[System.String,System.Management.Automation.ScriptBlock]]}
#=> GetLogsString     : PolarisLogs
#=> ClassDefinitions  :
#=> ContextHandler    : System.AsyncCallback
ターミナル(クライアント側)
PS> Invoke-RestMethod http://localhost:8080/helloworld
Hello World!

ターミナルをサーバーとクライアントとで2つに分けているのは、
Start-Polarisを実行したターミナルだとなぜかInvoke-WebRequestができなかったためです。
※Issuesにあるかと思いましたが、何も報告されていなかった。(仕様?環境による?)

CRUDのWeb-APIサンプル

以下、蔵書管理システムのCRUDをWeb-APIで実装していきます。
先ほどドット演算子で読み込んだ SampleServer.ps1 にWeb-APIのリソースを追加します。

各APIの仕様

~\Documents\Polaris内にFileStorageディレクトリを作成し、
1ファイル1書籍データでJSON形式に管理していきます。
ファイル名はユニークである必要があるため、ISBNコードを使用することにします。
以下、サンプルです。

~\Documents\Polaris\FileStorage\9781788838986.json
{
  "isbn" : 9781788838986,
  "title" : "Learn PowerShell Core 6.0",
  "publisher" : "Packt Publishing"
}

APIはもちろんCRUDなので、以下の4つを作成します。

Path Method Description
/books     POST    新しい書籍を登録します。               
/books     GET     一致するISBNの書籍情報を取得します。
/books     PUT     一致するISBNの書籍情報を更新します。
/books     DELETE    一致するISBNの書籍情報を削除します。

基本的に、RequestとResponseともapplication/jsonで通信させていきます。

下準備(Middlewareの実装)

先に~\Documents\Polaris\ディレクトリを作成しておきます。

ターミナル(サーバー側)
New-Item "~\Documents\Polaris\" -ItemType Director -Force

次に、各API特有のロジックに入る前に行う共通処理(Middleware)を実装します。
Middlewareですが、通常はOSとアプリケーションの間のプログラムを指す言葉ですが、
PlarisにおいてはPolarisとアプリケーションロジックの間(Middle)を示す用語として使用されています。

SampleServer.ps1
# $Request.BodyにRequestで受け取ったJSON文字列をオブジェクトとして格納する。
Use-PolarisJsonBodyParserMiddleware

# Requestで受け取った書籍情報を保存するディレクトリを作成、および、パスを設定する。
New-PolarisRouteMiddleware -Name FileStorage -Force -ScriptBlock {
  $PolarisPath = "~\Documents\Polaris\FileStorage"
  if (-not (Test-Path $PolarisPath)) {
    New-Item $PolarisPath -ItemType Directory > $null
  }

  $Request | Add-Member -Name PolarisPath -Value $PolarisPath -MemberType NoteProperty
}

修正したSampleServer.ps1を起動中のPolarisサーバーに適用したい場合は、
再度. .\SampleServer.ps1コマンドを実行すれば大丈夫です。
※以降も同様。

POST

それでは、新しい書籍を登録するAPIから実装をしていきます。

SampleServer.ps1
# 書籍登録API
New-PolarisPostRoute -Path "/books" -Force -Scriptblock {
  if (-not $Request.Body.ISBN -or -not $Request.Body.Title) {
    $Response.SetStatusCode(400)
    $Response.Send("ISBN or Title may not be empty.")
    return
  }

  New-Item -ItemType File -Path $Request.PolarisPath -Name "$($Request.Body.ISBN).json" -Value $Request.BodyString > $null
}

では、作成したAPIの動作確認をしていきます。

ターミナル(クライアント側)
# 修正を適用
PS> . .\SampleServer.ps1
# 1件目
PS> $book = @{isbn = 9781788838986; title = 'Learn PowerShell Core 6.0'; publisher = 'Packt Publishing'}
PS> Invoke-RestMethod http://localhost:8080/books -Method Post -Body ($book | ConvertTo-Json -Compress)
# 2件目
PS> $book = @{isbn = 9781633430297; title = 'Windows PowerShell in Action'; publisher = 'Manning Publications'}
PS> Invoke-RestMethod http://localhost:8080/books -Method Post -Body ($book | ConvertTo-Json -Compress)

# FileStorageに登録した書籍ごとにjsonファイルが作成されている。
PS> ls ~\Documents\Polaris\FileStorage
#=> 
#=>     ディレクトリ: C:\Users\uokeaj\Documents\FileStorage
#=> 
#=> Mode                LastWriteTime         Length Name
#=> ----                -------------         ------ ----
#=> -a----       2018/12/13     21:10             96 9781633430297.json
#=> -a----       2018/12/13     21:10             89 9781788838986.json

GET

次に、一致するISBNの書籍情報を取得できるようにします。
リクエストパラメーターは$Request.Query['パラメーター名']で取得可能です。

SampleServer.ps1
# 書籍取得API
New-PolarisGetRoute -Path "/books" -Force -Scriptblock {
  $query = if ($Request.Query['isbn']) {$Request.Query['isbn']} else {'*'}
  $gciParams = @{
    Path        = $Request.PolarisPath
    Filter      = "$($query).json"
    ErrorAction = 'SilentlyContinue'
  }

  $books = Get-ChildItem @gciParams | Foreach-Object {$_ | Get-Content | ConvertFrom-Json}
  $Response.Send(($books | ConvertTo-Json));
}
ターミナル(クライアント側)
# 修正を適用
PS> . .\SampleServer.ps1
# 1件だけ取得
PS> Invoke-RestMethod http://localhost:8080/books?isbn=9781633430297

#=> publisher            title                                 isbn
#=> ---------            -----                                 ----
#=> Manning Publications Windows PowerShell in Action 9781633430297

# 全件取得
PS> Invoke-RestMethod http://localhost:8080/books

#=> publisher            title                                 isbn
#=> ---------            -----                                 ----
#=> Manning Publications Windows PowerShell in Action 9781633430297
#=> Packt Publishing     Learn PowerShell Core 6.0    9781788838986

PUT

今度は、一致するISBNの書籍情報を更新します。
POSTの時と実装の仕方はあまり変わりません。

SampleServer.ps1
# 書籍更新API
New-PolarisPutRoute -Path "/books" -Force -Scriptblock {
  if (-not $Request.Body.ISBN -or -not $Request.Body.Title) {
    $Response.SetStatusCode(400)
    $Response.Send("ISBN or Title may not be empty.")
    return
  }

  Set-Content -Path (Join-Path $Request.PolarisPath "$($Request.Body.ISBN).json") -Value $Request.BodyString
}
ターミナル(クライアント側)
# 修正を適用
PS> . .\SampleServer.ps1
# 試しに、'Learn PowerShell Core 6.0'の出版社情報を省略した状態で更新してみます。
PS> $book = @{isbn = 9781788838986; title = 'Learn PowerShell Core 6.0'}
PS> Invoke-RestMethod http://localhost:8080/books -Method Put -Body ($book | ConvertTo-Json -Compress)

# publisherプロパティが消えていることが確認できました。
PS> Invoke-RestMethod http://localhost:8080/books?isbn=9781788838986

#=>          isbn title
#=>          ---- -----
#=> 9781788838986 Learn PowerShell Core 6.0

DELETE

最後に、一致するISBNの書籍情報を削除できるようにします。
こちらも、POST・PUTとあまり変わりません。

SampleServer.ps1
# 書籍削除API
New-PolarisDeleteRoute -Path "/books" -Force -Scriptblock {
  if (-not $Request.Body.ISBN) {
    $response.SetStatusCode(400)
    $response.Send("ISBN may not be empty.")
    return
  }

  Remove-Item -Path (Join-Path $Request.PolarisPath "$($Request.Body.ISBN).json")
}
ターミナル(クライアント側)
# 修正を適用
PS> . .\SampleServer.ps1
PS> Invoke-RestMethod http://localhost:8080/books -Method Delete -Body '{"isbn":9781788838986}'
# 削除できていることが確認できました。
PS> Invoke-RestMethod http://localhost:8080/books?isbn=9781788838986
#=> No output

Webページの表示方法

Polarisでは、まだテンプレートエンジンで動的なWebページ画面を生成する機能はないですが、
静的ページであれば、New-PolarisStaticRouteというコマンドレットで簡単に表示させることができます。

ターミナル(サーバー側)
PS> New-Item "~\Documents\Polaris\Public" -ItemType Director -Force

PS> @"
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>Hello world!</title>
  </head>
  <body>
    PolarisでHTMLページを表示しました。
  </body>
</html>
"@ | Out-File "~\Documents\Polaris\Public\index.html" -Encoding utf8

PS> New-PolarisStaticRoute -RoutePath 'public' -FolderPath "~\Documents\Polaris\Public" -Force
PS> Start-Process http://localhost:8080/public/index.html

すると、下記のようにWebページを表示することができます。
image.png

現在、PSHTMLというDSLでもっとHTMLソースを扱いやすくできるようにするための提案がされています。
RFC #002: Bundle PSHTML with Polaris #165
今後のアップデートに注目ですね。

参考文献

Polaris docs
Preview Online Code Files Learn PowerShell Core 6.0


  1. Polaris(ポラリス、pəlˈærɪs : 北極星)という命名ですが、おそらく、PowerShell + Solaris から来ていると思われます。(推測) 

  2. 発足時はコア部分だけC#で実装されていましたが、2018年4月頃に「WIP: Pure PowerShell Implementation」でPowerShellのみを使用するようにリファクタリングされました。 

  3. 配布先:PowerShell Gallery 

21
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
13