LoginSignup
5

More than 3 years have passed since last update.

Classic ASPによるRESTful APIのルーティング実装例

Last updated at Posted at 2019-12-19

この記事はZOZOテクノロジーズ #1 Advent Calendar 2019 20日目の記事です。

はじめに

同じエンドポイントのAPIでも、HTTPメソッドによって実行内容が変化するルーティング処理を、Classic ASP(VBScript)で実装してみます。

大事なのはこの三点です。

  1. Request.ServerVariables("REQUEST_METHOD")でHTTPメソッドを取得する。
  2. Request.ServerVariables("URL")で取得したURLからリソース名を取得する。
  3. GetRefを使って文字列で実行する処理を決める。

実装

これから実装する、エンドポイント・HTTPメソッド・実行される関数は、それぞれ表の通りです。

エンドポイント HTTPメソッド 実行される関数
https://example.com/api/v1/hoges
POST CreateHoges
GET ReadHoges
https://example.com/api/v1/fugas
POST CreateFugas
GET ReadFugas

※今回はDELETEやPUTなどの更新系については触れません。

1. HTTPメソッドからCRUDを特定する

HTTPメソッドからCRUDのどの操作をするか決めます。

Request.ServerVariables("REQUEST_METHOD") でHTTPメソッドを取得することができます。
ここではCRUDのいずれかの文字列を返す関数を作成します。

/api/v1/router.asp

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から不要な文字列を除去して、リソース名を取得する関数を作ります。

/api/v1/router.asp

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とリソース名を組み合わせて関数名を組み立てる

先ほど作った二つの関数を組み合わせるだけです。

/api/v1/router.asp

Function GetFuncName()
    GetFuncName = (GetCrudByHttpMethod() & GetResourceNameByUrl())
End Function

例えば https://example.com/api/v1/hoges がGETで呼び出された場合、戻り値はReadHogesとなります。

4. 関数の場所を見つける

VBScriptの組み込み関数GetRefを用いて、メモリ内での関数の場所(アドレス)を取得する処理を作成します。
GetRefはC言語などで言うところの「関数ポインタ」です。

先ほど組み立てた関数名をGetRefの引数で渡します。
存在しない関数名を指定するとエラーになるので、On Errorステートメントを使って回避しています。
また初期値にNothingをセットすることで、存在しない関数であることが、呼び出し元でもわかるようになります。

/api/v1/router.asp

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で判定して制御します。

/api/v1/router.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

実行

1. 準備

あらかじめ下記のファイルを用意しておきます。
存在しない関数の挙動を確認するためにCreateHogesはコメントアウトしておきます。

/api/v1/hoges/default.asp

<!-- #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. 別のエンドポイントで実行

続いて、異なるエンドポイントでも検証してみます。
以下のファイルを用意します。

/api/v1/fugas/default.asp

<!-- #include virtual="\api\v1\router.asp" -->
<%
Call Router()

Function ReadFugas()
    Response.write "ReadFugasが呼ばれました"
End Function
%>

https://example.com/api/v1/fugas をGETで実行します。

ReadFugasが呼ばれました

エンドポイントが変わっても、正常に動作していることが確認できました。

まとめ

大事なのはこの三点です。

  1. Request.ServerVariables("REQUEST_METHOD")でHTTPメソッドを取得する。
  2. Request.ServerVariables("URL")で取得したURLからリソース名を取得する。
  3. GetRefを使って文字列で実行する処理を決める。

ここまでで登場したコードは以下にまとめました。

/api/v1/router.asp

<%
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
%>
/api/v1/hoges/default.asp

<!-- #include virtual="\api\v1\router.asp" -->
<%
Call Router()

'存在しない関数を確認するためにコメントアウト
'Function CreateHoges()
'    Response.write "CreateHogesが呼ばれました"
'End Function

Function ReadHoges()
    Response.write "ReadHogesが呼ばれました"
End Function   
/api/v1/fugas/default.asp

<!-- #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

宜しければご覧ください。

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
5