この記事はZOZOテクノロジーズ #1 Advent Calendar 2019 20日目の記事です。
はじめに
同じエンドポイントのAPIでも、HTTPメソッドによって実行内容が変化するルーティング処理を、Classic ASP(VBScript)で実装してみます。
大事なのはこの三点です。
-
Request.ServerVariables("REQUEST_METHOD")
でHTTPメソッドを取得する。 -
Request.ServerVariables("URL")
で取得したURLからリソース名を取得する。 -
GetRef
を使って文字列で実行する処理を決める。
実装
これから実装する、エンドポイント・HTTPメソッド・実行される関数は、それぞれ表の通りです。
エンドポイント | HTTPメソッド | 実行される関数 |
---|---|---|
https://example.com/api/v1/hoges | ||
POST | CreateHoges | |
GET | ReadHoges | |
https://example.com/api/v1/fugas | ||
POST | CreateFugas | |
GET | ReadFugas |
1. HTTPメソッドからCRUDを特定する
HTTPメソッドからCRUDのどの操作をするか決めます。
Request.ServerVariables("REQUEST_METHOD")
でHTTPメソッドを取得することができます。
ここではCRUDのいずれかの文字列を返す関数を作成します。
Function GetCrudByHttpMethod()
Select Case Request.ServerVariables("REQUEST_METHOD")
Case "POST" GetCrudByHttpMethod = "Create"
Case "GET" GetCrudByHttpMethod = "Read"
Case "PUT" GetCrudByHttpMethod = "Update"
Case "DELETE" GetCrudByHttpMethod = "Delete"
End Select
End Function
2. URLからリソース名を特定する
Request.ServerVariables("URL")
でURLを取得することができます。
URLから不要な文字列を除去して、リソース名を取得する関数を作ります。
Const API_ENDPOINT_BASE_PATH_V1 = "/api/v1"
Const API_DEFAULT_ASP = "Default.asp"
Function GetResourceNameByUrl()
Dim resourceName : resourceName = Request.ServerVariables("URL")
resourceName = Replace(resourceName, API_ENDPOINT_BASE_PATH_V1, "")
resourceName = Replace(resourceName, API_DEFAULT_ASP, "")
resourceName = Replace(resourceName, "/", "")
GetResourceNameByUrl = resourceName
End Function
例えば https://example.com/api/v1/hoges の場合、戻り値はhoges
となります。
3. CRUDとリソース名を組み合わせて関数名を組み立てる
先ほど作った二つの関数を組み合わせるだけです。
Function GetFuncName()
GetFuncName = (GetCrudByHttpMethod() & GetResourceNameByUrl())
End Function
例えば https://example.com/api/v1/hoges がGETで呼び出された場合、戻り値はReadHoges
となります。
4. 関数の場所を見つける
VBScriptの組み込み関数GetRef
を用いて、メモリ内での関数の場所(アドレス)を取得する処理を作成します。
GetRef
はC言語などで言うところの「関数ポインタ」です。
先ほど組み立てた関数名をGetRefの引数で渡します。
存在しない関数名を指定するとエラーになるので、On Errorステートメントを使って回避しています。
また初期値にNothing
をセットすることで、存在しない関数であることが、呼び出し元でもわかるようになります。
Function GetFuncPointer(ByVal funcName)
Set GetFuncPointer = Nothing
'GetRefに存在しない関数名を指定するとエラーになる。
On Error Resume Next
Set GetFuncPointer = GetRef(funcName)
On Error GoTo 0
End Function
5. 関数を呼び出す
GetRef
で取得した関数ポインタは、Call
で呼び出せます。
つまりGetRef
を使うことで、文字列によって呼び出す関数を決めることができます。
存在しない関数の場合は、GetFuncPointer
で指定した初期値のNothing
で判定して制御します。
Sub Router()
Dim funcName : funcName = GetFuncName()
Dim FuncPointer : Set FuncPointer = GetFuncPointer(funcName)
If FuncPointer Is Nothing Then
Response.write funcName & "は存在しません"
Else
Call FuncPointer()
End If
End Sub
実行
1. 準備
あらかじめ下記のファイルを用意しておきます。
存在しない関数の挙動を確認するためにCreateHoges
はコメントアウトしておきます。
<!-- #include virtual="\api\v1\router.asp" -->
<%
Call Router()
'存在しない関数を確認するためにコメントアウト
'Function CreateHoges()
' Response.write "CreateHogesが呼ばれました"
'End Function
Function ReadHoges()
Response.write "ReadHogesが呼ばれました"
End Function
2. GETで実行
https://example.com/api/v1/hoges をGETで実行します。
ReadHogesが呼ばれました
HTTPメソッドがGETなので、hogesをreadする処理が呼び出されました。
3. POSTで実行
https://example.com/api/v1/hoges をPOSTで実行します。
Createhogesは存在しません
CreateHoges
はコメントアウトしたので呼び出されません。
関数の有無も正しく判定できていることが確認できました。
4. 別のエンドポイントで実行
続いて、異なるエンドポイントでも検証してみます。
以下のファイルを用意します。
<!-- #include virtual="\api\v1\router.asp" -->
<%
Call Router()
Function ReadFugas()
Response.write "ReadFugasが呼ばれました"
End Function
%>
https://example.com/api/v1/fugas をGETで実行します。
ReadFugasが呼ばれました
エンドポイントが変わっても、正常に動作していることが確認できました。
まとめ
大事なのはこの三点です。
-
Request.ServerVariables("REQUEST_METHOD")
でHTTPメソッドを取得する。 -
Request.ServerVariables("URL")
で取得したURLからリソース名を取得する。 -
GetRef
を使って文字列で実行する処理を決める。
ここまでで登場したコードは以下にまとめました。
<%
Const API_ENDPOINT_BASE_PATH_V1 = "/api/v1"
Const API_DEFAULT_ASP = "Default.asp"
Sub Router()
Dim funcName : funcName = GetFuncName()
Dim FuncPointer : Set FuncPointer = GetFuncPointer(funcName)
If FuncPointer Is Nothing Then
Response.write funcName & "は存在しません"
Else
Call FuncPointer()
End If
End Sub
Function GetFuncName()
GetFuncName = (GetCrudByHttpMethod() & GetResourceNameByUrl())
End Function
Function GetCrudByHttpMethod()
Select Case Request.ServerVariables("REQUEST_METHOD")
Case "POST" GetCrudByHttpMethod = "Create"
Case "GET" GetCrudByHttpMethod = "Read"
Case "PUT" GetCrudByHttpMethod = "Update"
Case "DELETE" GetCrudByHttpMethod = "Delete"
End Select
End Function
Function GetResourceNameByUrl()
Dim resourceName : resourceName = Request.ServerVariables("URL")
resourceName = Replace(resourceName, API_ENDPOINT_BASE_PATH_V1, "")
resourceName = Replace(resourceName, API_DEFAULT_ASP, "")
resourceName = Replace(resourceName, "/", "")
GetResourceNameByUrl = resourceName
End Function
Function GetFuncPointer(ByVal funcName)
Set GetFuncPointer = Nothing
On Error Resume Next
Set GetFuncPointer = GetRef(funcName)
On Error GoTo 0
End Function
%>
<!-- #include virtual="\api\v1\router.asp" -->
<%
Call Router()
'存在しない関数を確認するためにコメントアウト
'Function CreateHoges()
' Response.write "CreateHogesが呼ばれました"
'End Function
Function ReadHoges()
Response.write "ReadHogesが呼ばれました"
End Function
<!-- #include virtual="\api\v1\router.asp" -->
<%
Call Router()
Function CreateFugas()
Response.write "CreateFugasが呼ばれました"
End Function
Function ReadFugas()
Response.write "ReadFugasが呼ばれました"
End Function
%>
参考
ServerVariables | Microsoft Docs
GetRef 関数 | Microsoft Docs
明日は@takanamitoさんの記事です!
また、今年は全部で5つのAdvent Calendarが公開されています。
ZOZOテクノロジーズ #1 Advent Calendar 2019
ZOZOテクノロジーズ #2 Advent Calendar 2019
ZOZOテクノロジーズ #3 Advent Calendar 2019
ZOZOテクノロジーズ #4 Advent Calendar 2019
ZOZOテクノロジーズ #5 Advent Calendar 2019
宜しければご覧ください。