Webアクションを実行する
Webアクションとは、Webベースのアプリケーションを素早く構築できるようにサポートするCloud Functionsアクションです。 Webアクションを利用すると、別途のCloud Functionsの認証キーなしに誰でもWebアプリケーションにアクセス可能なバックエンドロジックを作ることができます。
もし、別途の認証ロジックが必要であれば、希望する認証ロジックを直接実現した利用したり、API GatewayでAPI KeyとIAM認証とを利用することができます。
Webアクションを作成する
以下の例は、demo
パッケージ内にhello
という名前でWebアクションを作る例です。
まず、以下のようなコードでhello
というJavaScriptコードを作ります。
hello nodejs Actionコードの例
function main({name}) {
var msg = 'you did not tell me who you are.';
if (name) {
msg = `hello ${name}!`
}
return {body: `<html><body><h3>${msg}</h3></body></html>`}
}
その後、demo
名をもつパッケージを作ります。
皆様が現在guest
ネームスペースを使うと仮定したため、アクションのパスが/guest/
から始まったが、お使いになるネームスペースに合わせて修正してください。
Web
オプションと利用する場合に作成されるアクションは、別途の認証なしにRESTインターフェースを利用してアクセスすることができる状態になります。
Webアクションを実行する
Webアクションは、一般のActionと違って、様々な形式の出力に対応するため、API Gatewayを利用して作成されるURLにTypeを明示できる区間が追加されます。type値は、明示的に追加しなければならず、URLパラメータは、Typeの最後に?name=name1
形式で追加することができます。
作成されたWebプロパティActionのAPI Gateway URL例
https://l2lwhxikt4.apigw.ntruss.com/api/dev/ZGUVjLH0ZT/{type+}
上記のURLを解釈すると、次のような形式で構成されます。
https://{product_id}.apigw.ntruss.com/{api_name}/{stage_name}/{resource_name}/{type+}
- product_id:API Gatewayに作成したproduct IDです。
- api_name:API Gatewayに作成したapi名です。
- stage_name:API Gatewayに作成して配布したstage名です。
- resource_name:API Gatewayに作成したresource名です。Cloud functionsでは、別のリソースを上書きして生じる問題を防止しようと、resource名はランダムに作成します。
- type+:リクエストレスポンスをどのような形式で構成するかに対するType値です。現在、
/json
、/http
、/svg
、/html
、/text
などに対応可能です。
Curl
$ curl https://l2lwhxikt4.apigw.ntruss.com/api/dev/ZGUVjLH0ZT/{type+}
Webアクションの利用例
この例は、HTTP redirectを実行するWebアクションの例です。
function main() {
return {
headers: { location: 'http://NCP-CloudFunctions.com' },
statusCode: 302
}
}
この例は、ヘッダーにcookieを設定する例です。
function main() {
return {
headers: {
'Set-Cookie': 'UserID=Jane; Max-Age=3600; Version=',
'Content-Type': 'text/html'
},
statusCode: 200,
body: '<html><body><h3>hello</h3></body></html>' }
}
この例は、様々なcookieを設定する例です。
function main() {
return {
headers: {
'Set-Cookie': [
'UserID=Jane; Max-Age=3600; Version=',
'SessionID=asdfgh123456; Path = /'
],
'Content-Type': 'text/html'
},
statusCode: 200,
body: '<html><body><h3>hello</h3></body></html>' }
}
この例は、コンテンツタイプをimage/png
に設定し、base64
の文字列を通じてイメージを返す例です。
function main() {
let png = <base 64 encoded string>
return { headers: { 'Content-Type': 'image/png' },
statusCode: 200,
body: png };
}
この例は、application/json
タイプでjsonを返す例です。
function main(params) {
return {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: params
};
}
HTTPレスポンスで利用されるベーシックContent-Type値は、application/json
であり、本文にはJSON値を入力することができます。ベーシックContent-Typeは、ヘッダーから省略することができます。
アクションが返せるレスポンスの最大サイズは制限(Limit)されており、制限値を超過してレスポンスを返すと、アクションに失敗します。大きなオブジェクトファイルは、Cloud Functionsコードで返さずに別のレジストリを利用してください。
アクションでHTTPリクエストを取り扱う
WebアクションでないCloud Functionsのアクションは、基本的に認証を要求し、必ずJSONオブジェクトを返す必要があります。一方、Webアクションは、認証なしに実行することができ、headers、statusCode、bodyなど、多様なコンテンツでレスポンスするHTTPハンドラーを実現するのに利用されます。
Webアクションは、依然としてJSONオブジェクトを返さなければならないが、Cloud Functionsシステムのコントローラは、JSONオブジェクトの最上位のプロパティとして、次の項目のうちの1つ以上を含む場合、Webアクションを異なるように処理します。
headers
:キーがヘッダー名であり、値が文字列、数字、或いはboolean値からなるJSONオブジェクトです。1つのヘッダーとして複数値を送る場合には、ヘッダーの値がJSON配列で構成されている必要があります。statusCode
:有効なHTTPステータスコードです。(基本値は200 OKであり、bodyが空いている場合、204 No Contentで返されます)body
:一般テキスト、JSONオブジェクト又は配列である文字列又はbase64でエンコードされたバイナリーデータになれます。(基本値は、空レスポンスです)
body
がnull
である場合、空文字列の""
そしてundefinedは、コンテンツがないと判断します。
コントローラは、アクションで指定したヘッダーをリクエスト/レスポンスを終了する際、HTTPクライアントに転送します。それと同様に、コントローラは、与えられたステータスコードでレスポンスします。最後に、bodyはレスポンスのbodyで転送されます。もし、content-type header
が結果のheaders
に定義されていなければ、bodyは本文が文字列でない場合に対し、application/json
で解釈され、それ以外はtext/html
と解釈されます。
もし、content-type
が定義されていれば、コントローラはレスポンスが二進データや一般のテキストである場合、必要に応じて、base64デコーダーで文字列をデコードします。このとき、本文が正しくデコードされていなければ、呼び出し人にエラーが返されます。
HTTP Context
全てのWebアクションは呼び出された際、次のような追加のHTTPリクエスト情報を入力パラメータとして受けます。
__ow_method
(タイプ:string):リクエストのHTTPメソッド__ow_headers
(タイプ:map string to string):リクエストヘッダー__ow_path
(タイプ:string):the unmatched path of the request (matching stops after consuming the action extension).__ow_user
(タイプ:string):Cloud Functionsのネームスペース__ow_body
(タイプ:string):リクエスト本文であり、内容がバイナリー又はJSONオブジェクト/配列である場合、base64でエンコードされた文字列を返し、そうでない場合には、一般の文字列を返す。__ow_query
(タイプ:string):クエリパラメータからパーシングされない文字列
リクエストは、上記で述べたような__ow_
パラメータを上書きしません。もし、上書きしようとする場合、400 Bad Requestのような状態を返してリクエストに失敗します。
__ow_user
は、Webアクションがauthenticationを要求するようにした場合にのみ表示され、開発者が直接認証ポリシーを実現できるように許容します。__ow_query
は、専らWebアクションが"raw" HTTPリクエストを処理するように選択した場合にのみ処理することができます。この変数は、&で区分され、URIからパーシングされたクエリパラメータの含まれた文字列です。__ow_body
プロパティは、"raw" HTTPリクエストを処理したりリクエストエンティティがJSONオブジェクト又はform dataでない場合に存在します。
追加機能
Webアクションは、以下のような追加機能を提供します。
- Content extensions:希望するコンテンツタイプを
/json
、/html
、/http
、/svg
、/text
のうちの1つに指定します。URIのアクション名に拡張子を追加することで実行され、/{Web_Action_URL}
アクションはHTTPレスポンスを受けるために、/{Web_Action_URL}/http
のように使われます。typeがない場合は、実行されません。 - Projecting fields from the result:
/http
でない別のコンテンツ拡張子とともに使用されます。アクション名の後についてくるパスは、1つ或いは複数レベルのレスポンスを投影して見せるために使用されます。例えば、/{Web_Action_URL}/html/body
のようなリクエストを行うと、{body: "..." }
形式のディクショナリーを返すアクションの場合、body
のプロパティを選択して文字列値を直接返します。このようなパスは、必ずパスモデルに従います( XPathを参照)。 - Query and body parameters as input:アクションは、リクエスト本文のパラメータだけでなく、クエリパラメータを受けます。このようなパラメータを組み合わせる際、優先順位は、パッケージパラメータ、アクションパラメータ、クエリパラメータの順であり、重なる場合はそれぞれの以前の値を順番通りに再定義します。例えば、
/{Web_Action_URL}/http/?name=Jane
のようなリクエストは、入力パラメータで{name: "Jane"}
をアクションに転送します。 - Form data:標準の
application/json
の他にも、WebアクションはURLエンコードされたform dataapplication/x-www-form-urlencoded data
も入力されることができます。 - Activation via multiple HTTP verbs:Webアクションは、HTTPメソッドから実行することができます。(
GET
、POST
、PUT
、PATCH
、DELETE
、HEAD
、OPTIONS
) - Non JSON body and raw HTTP entity handling:Webアクションは、JSONオブジェクトの他のHTTPリクエストbodyを処理することができ、理解が困難な値も常に受けるように選択することができます(バイナリーでない場合、一般の文字列又はbase64でエンコードされた文字列)。
以下の例は、Webアクションでこのような機能を利用することができる方法を概略に示します。
function main(params) {
return { response: params };
}
上記例のコードを利用してアクションが受ける因子が何かを確認するために、全てのオブジェクトを返して確認します。
$ curl https://{Action_URL}/json
{
"response": {
"__ow_method": "get",
"__ow_headers": {
"accept": "*/*",
"connection": "close",
"host": "172.17.0.1",
"user-agent": "curl/7.43.0"
},
"__ow_path": ""
}
}
クエリパラメータとともに実行します。
$ curl https://{Action_URL}/json?name=Jane
{
"response": {
"name": "Jane",
"__ow_method": "get",
"__ow_headers": {
"accept": "*/*",
"connection": "close",
"host": "172.17.0.1",
"user-agent": "curl/7.43.0"
},
"__ow_path": ""
}
}
form dataとともに実行します。
$ curl https://{Action_URL}/json -d "name":"Jane"
{
"response": {
"name": "Jane",
"__ow_method": "post",
"__ow_headers": {
"accept": "*/*",
"connection": "close",
"content-length": "10",
"content-type": "application/x-www-form-urlencoded",
"host": "172.17.0.1",
"user-agent": "curl/7.43.0"
},
"__ow_path": ""
}
}
JSONオブジェクトとともに実行します。
$ curl https://{Action_URL}/json -H 'Content-Type: application/json' -d '{"name":"Jane"}'
{
"response": {
"name": "Jane",
"__ow_method": "post",
"__ow_headers": {
"accept": "*/*",
"connection": "close",
"content-length": "15",
"content-type": "application/json",
"host": "172.17.0.1",
"user-agent": "curl/7.43.0"
},
"__ow_path": ""
}
}
単に名前を文字列に投影(project)します。既に言及したProjecting fields from the resultの追加機能に対する使用例です。
$ curl https://{Action_URL}?name=Jane
Jane
上記の例でクエリパラメータ、フォームデータ、そしてJSONオブジェクト本文のいずれも直接アクセスできるアクション入力パラメータとして手軽に処理されることを確認することができます。
しかし、WebアクションがJSONオブジェクトをエンティティとして受ける場合でないか、リクエストエンティティを直接処理する場合は、それに当てはまりません。例えば、"text" content-typeでコード例を利用してエンティティを転送した場合、以下のように__ow_body
に因子が入ってくることを確認することができます。
$ curl https://{Action_URL} -H 'Content-Type: text/plain' -d "Jane"
{
"response": {
"__ow_method": "post",
"__ow_headers": {
"accept": "*/*",
"connection": "close",
"content-length": "4",
"content-type": "text/plain",
"host": "172.17.0.1",
"user-agent": "curl/7.43.0"
},
"__ow_path": "",
"__ow_body": "Jane"
}
}
コンテンツ拡張子
コンテンツ拡張子は、アクションを呼び出す際に使われます。拡張子/json
は、投影パス(projection path)を要求せず、拡張子/http
は、このようなパスに対応していません。しかし、拡張子/html
、/svg
そして/text
は、投影パスを要求します。便利なご利用のために、基本パスは拡張子名と一致すると仮定します。よって、Webアクションを実行し、/html
レスポンスを受けるために、アクションはhtml
という最上位のプロパティを含むJSONオブジェクトでレスポンスしなければなりません。(又は、レスポンスが明示的に与えられたパスにある必要があります。)
即ち、{Action_URL}/html
は、{Action_URL}/html/html
の例のように、htmlプロパティを明示的に投影するのと同様です。パスに利用されるアクションの完全な名前は、パッケージ名を必ず含めなければならず、パッケージがない場合、基本値はdefault
です。
パラメータの保護
アクションパラメータは、保護されて不変するプロパティで管理されます。Webアクションが有効になれば、パラメータは自動的に不変に設定されます。
{
"name":"Jane"
}
このような変更の結果として、name
のプロパティは、Jane
でバインディングされており、不変であるため、クエリや本文のパラメータで上書きすることができません。このようにすることで、ミスで或いは意図的に値を変更しようとするクエリ又は本文の媒介変数に対してアクションを保護するようになります。
Raw HTTPの処理
Webアクションは、入ってくるHTTP本文を解釈して処理するように選択することができます。JSONオブジェクトをアクション入力で使用可能な第1級オブジェクトのプロパティに昇格させる必要はありません(例えば、args.name
vs parsing args.__ow_query
)。これらは、raw-http
を利用して行われます。
上記でお見せしたように、簡単な例を通じて、name
のプロパティをクエリパラメータとリクエスト本文をJSON値で受ける例を'raw'Webアクションで実行してみます。
$ curl https://{Action_URL}/json?name=Jane -X POST -H "Content-Type: application/json" -d '{"name":"Jane"}'
{
"response": {
"__ow_method": "post",
"__ow_query": "name=Jane",
"__ow_body": "eyJuYW1lIjoiSmFuZSJ9",
"__ow_headers": {
"accept": "*/*",
"connection": "close",
"content-length": "15",
"content-type": "application/json",
"host": "172.17.0.1",
"user-agent": "curl/7.43.0"
},
"__ow_path": ""
}
}
Cloud Functionsは、Akka Httpのフレームワークを利用し、バイナリーと一般のテキストコンテンツタイプを判断します。
Base64タイプのバイナリー本文のデコード
Raw HTTPで処理する際、content-typeがバイナリーである場合 __ow_body
コンテンツは、Base64でエンコードされているはずです。以下の関数は、Node、Python、そしてSwiftでエンコードされた本文をどのように取り扱うか示します。
簡単に以下の関数を保存し、Raw HTPのWebアクションを作成してWeb作業を実行してテストを行うことができます。
Node
function main(args) {
decoded = new Buffer(args.__ow_body, 'base64').toString('utf-8')
return {body: decoded}
}
Python
def main(args):
try:
decoded = args['__ow_body'].decode('base64').strip()
return {"body": decoded}
except:
return {"body": "Could not decode body from Base64."}
Swift
extension String {
func base64Decode() -> String? {
guard let data = Data(base64Encoded: self) else {
return nil
}
return String(data: data, encoding: .utf8)
}
}
func main(args: [String:Any]) -> [String:Any] {
if let body = args["__ow_body"] as? String {
if let decoded = body.base64Decode() {
return [ "body" : decoded ]
}
}
return ["body": "Could not decode body from Base64."]
}
NodeJS関数をdecode
のActionで保存し、それを以下のコマンドで実行してテストを行うことができます。
$ curl -k -H "content-type: application" -X POST -d "Decoded body" https://{Action_URL}/json
{
"body": "Decoded body"
}
Optionsリクエスト
基本的に、OPTIONSリクエストは、CORSヘッダーが自動的にレスポンスヘッダーに追加されます。このようなヘッダーは、全てのoriginsに対して許容され、options、get、delete、post、put、head、そしてpatch HTTPを許容します。
更に、HTTPリクエストに存在する場合、Access-Control-Request-Headers
ヘッダーはAccess-Control-Allow-Headers
ヘッダーでエコーバックされます。基本値は、以下のように作成されます。
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS, GET, DELETE, POST, PUT, HEAD, PATCH
Access-Control-Allow-Headers: Authorization, Content-Type
又は、OPTIONSリクエストは、Webアクションによってマニュアルにして処理されることができます。このオプションを有効にするために、web-custom-options
オプションをtrue
値で有効化させます。この機能が有効になれば、CORSヘッダーはそれ以上自動的に追加されません。その代わりに、開発者が追加すべき責任があり、プログラミングでヘッダーを決めることができます。
以下の例は、OPTIONSリクエストに対するカスタムレスポンスコードの例です。
function main(params) {
if (params.__ow_method == "options") {
return {
headers: {
'Access-Control-Allow-Methods': 'OPTIONS, GET',
'Access-Control-Allow-Origin': 'example.com'
},
statusCode: 200
}
}
}
上記の関数を保存してコマンドを実行すると、以下のような結果を得ることができます。
$ curl https://{Action_URL}/http -kvX OPTIONS
< HTTP/1.1 200 OK
< Server: nginx/1.11.13
< Content-Length: 0
< Connection: keep-alive
< Access-Control-Allow-Methods: OPTIONS, GET
< Access-Control-Allow-Origin: example.com
エラーの処理
Cloud Functionsアクションに失敗した場合、2つの失敗モードで処理されます。一番目は、application errorで知られており、catchの例外と類似します。アクションは、errorプロパティを有する最上位のJSONオブジェクトを返します。二番目は、developer errorで、アクションに失敗してレスポンスを作らない時に発生します。uncaughtの例外と類似します。
Webアクションで、コントローラは、アプリケーションエラーを次のように処理します。
- 指定された投影パスがあれば無視され、コントローラは、
error
プロパティを代わりに利用します。 - コントローラは、action extensionによって含まれた内容を
error
プロパティ値に適用します。
開発者は、Webアクションがどのように利用されるかを知り、それに応じたエラーメッセージを作成する必要があります。例えば、拡張子.http
とともに利用されるWebアクションは、{error: { statusCode: 400 }
のようなHTTPレスポンスを返さなければなりません。そうしないと、拡張子のcontent-typeとエラーのレスポンスアクションのcontent-typeとが一致しなくなります。
シーケンスを構成するコンポーネントは、適切なエラーを、必要な時に作成できるようにしなければなりません。
関連情報へ
下のガイドから関連情報をご確認いただけます。