ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Elixir Phoenix : Router와 Controller
    Elixir 프로그래밍 2019. 10. 8. 01:21

    Router는 request URI를 어떤 모듈의 어떤 함수가 처리할지를 지정하는 모듈입니다.

     

    router 모듈내에는 복수개의 pipeline을 둘수 있으며, pipeline은 http request를 받았을 때 해야하는 일련의 일들의 모임이라 생각할 수 있습니다. 

     

    위의 소스코드에서는 두개의 pineline이 있으며, :browser와 :api로  각각 html request와 json api 를 처리하는 경우에 대한 정의라고 생각하면 됩니다.  이에 대한 자세한 설명은  https://hexdocs.pm/phoenix/routing.html#pipelines을 참조하면 되며, 일반적인 경우 이에 대한 기능 추가는 하지 않아도 됩니다. 

     

    위의 코드에서 중요한 부분은 

     

      scope "/"HelloWebWeb do

        pipe_through :browser

     

        get "/"PageController, :index 

        get "/hello" , PageController, :hello

        get "/now" , PageController, :now

        get "/calc" , PageController, :calc

      end

     

    부분입니다. 이는  어떤 URI 에 대해 어떤 method 요청을 , 어떤 모듈의 어떤 함수가 처리할지를 지정합니다.

    위의 예에서, 

     

    http의 GET method로 /hello URI 가 요청되는 경우, PageController의 :hello 함수를 호출하도록 지정한 것 입니다. 

    동일 PC에서 실행하는 경우에는 브라우저의 http://localhost:4000/hello 를 입력하면, PageController 모듈의 :hello 함수가 호출되고

    :hello 함수의 결과값이 브라우저에 response로 전송됩니다. 

     

    위의 코드에서는 /hello, /now, /calc 에 대해 처리할 함수를 지정하였습니다. 

     

    다음은 PageController.ex의 소스코드 입니다. 

     

    코드에는 위의 router에서 지정한 함수들이 있습니다. 

     

    각 함수들은   

      def hello(conn,_paramdo

        html conn, """

        <HTML>

        <HEAD>

        <TITLE> Hello !! </TITLE> </HEAD>

        <BODY>

            <h1> Hello Phoenix Web </h1>

        </BODY>

        </HTML>  

        """

      end

    와 같이. conn 과 param을 인자로 받습니다.

     

    인자 conn은  http의 request에 대한 정보와 response 정보를 가지는 map 구조체 입니다.

    conn에는 request 정보로, 호출된 method 와 상대의 ip 주소, header 정보등 http request의 모든 정보를 가지고 있습니다.

     

    controller 함수는 이 conn에 response 정보를 저장하여 반환하면, 그 결과가 클라이언트(브라우저)측에 전송되게 됩니다.

    즉, controller 함수의 결과값은 항상 conn 이여야 합니다.

     

     

    위의 코드에서 html conn, """ ... """ 은,   Phoenix.Controller.html(conn, """...""") 함수를 호출하는 것 입니다.

    Phoenix.Controller.html(conn, """...""") 를 html conn, """...""" 으로 호출할 수 있는 것은, 소스코드의 위에 있는 

    useHelloWebWeb, :controller이 있기 때문입니다. (자세한 내용은 본 글에서는 생략하며, 이의 내용을 몰라도 개발에 문제가 없습니다.)

     

    Phoenix.Controller.html 함수는 두번째 파라미터로 주어진 데이터를 html 화하여 첫번째 파라이터인 conn에 response 정보를 저장하고 conn을 return 합니다 (response의 content-type: text/html).  이런 흐름이기 때문에 위의 hello 함수는 html response 정보가 저장된 conn을 return 하고, 그 정보가 클라이언트에게 전송됩니다. 

     

    conn은 Plug.Conn 타입이며, 이에 대한 상세한 정보는 

    https://hexdocs.pm/plug/Plug.Conn.htm

    https://devhints.io/phoenix-conn를 참조하세요. 

     

     

    아래의 함수는  URI /now 에 대한 처리 함수로, 현재 시간을 보여주는 HTML을 응답으로 전송합니다. 

      def now(conn,_paramdo

        now = :calendar.local_time() |> NaiveDateTime.from_erl! |> NaiveDateTime.to_string

     

        html conn, """

        <HTML>

        <HEAD>

        <TITLE> Now </TITLE> </HEAD>

        <BODY>

            <h1> #{now} </h1>

        </BODY>

        </HTML>  

        """

      end

     

    위의 hello 와 거의 비슷하지만,  현재 시간을 문자열로 만들고 이를 HTML 문자열내에 string interpolation으로 표현한 것 입니다.

     

    이와 같이 string interpolation 을 통하여 HTML에 변수의 값이나 DB의 쿼리 결과값등을 넣을수 있지만, 이를 좀더 편하고 일반화한것이 Template와 View 모듈입니다. (이에 대한 설명은 다음글에 적겠습니다.)

     

     

     

    세번째 함수, calc는 두수를 URI의 인자로 받아서 그 결과값을 JSON 타입(content-type: application/json)으로 반환하는 Rest API함수를 구현한 것입니다.

     

      def calc(conn,%{"a" => valueA , "b" => valueB}) do

        sumValue = String.to_integer(valueA) + String.to_integer(valueB)

        json conn, %{result: :ok, sum: sumValue}       

      end

     

      def calc(conn,_paramdo

        json conn, %{result: :error}    

      end

     

    위의 함수는 http://localhost:4000/calc?a=1&b=2 와 같이 호출하면되며, 

    URI  인자 a=1&b=2 는 calc 함수의 두번째 인자인 param에 map의 형태로 전달됩니다. 

     

    함수 calc(conn,%{"a" => valueA , "b" => valueB})  에서는 

    인자로 주어진 두값을 pattern matching으로 가져와서 , 두수의 합을 계산한후 그 결과를 JSON으로 반환합니다.

    map에 주어진 인자값은 문자열이므로, 두수의 계산을 수행하기 전에 정수형으로 변환한 후 계산을 수행하도록 구현되어 있습니다.

     

    Phoenix.Controller.html(conn, """...""") 이 HTML 결과를 반환하는 것에 반해, 

    Phoenix.Controller.json(conn,  json_data) 는 결과값을 JSON type으로 반환 합니다. 

     

    와 같이, 결과의 content-type이 application/json으로 되어 있는 것을 확인할 수 있습니다.

     

    json 함수는 두번째 인자로 JSON으로 변환될 수 있는 모든 자료형을 줄수 있습니다. 이는 List, Map 등이며, JSON 으로 변환될 수 있는 자료형이면, 내부에서 자동으로 JSON 형식으로 변환합니다. 

     

     

    같은 이름의 함수, calc 

      def calc(conn,%{"a" => valueA , "b" => valueB}) do

      def calc(conn,_paramdo

    가 두개 있는 것은,  URI 인자로 a,b가 주어지지 않은 경우에 대한 처리 목적입니다.

     

    http://localhost:4000/calc?a=1&b=2 또는 http://localhost:4000/calc?a=1&b=2&c=3 와 같이 

    a와 b 가 주어진 경우 (또는 그 외의 값이 주어진 경우도 포함)에는 pattern matching  %{"a" => valueA , "b" => valueB} 에 맞으므로

    함수 calc(conn,%{"a" => valueA , "b" => valueB})가 호출되며, 

     

    http://localhost:4000/calc 또는 http://localhost:4000/calc?a=1  또는 http://localhost:4000/calc?b=2

    와 같이  a와 b가 모두 주어지지 않는 모든 경우에 대해서는  calc(conn,_param)가 호출됩니다. 

     

    이와 같은 방식으로, pattern matching으로  Rest API 구현시 함수의 인자 체크를 쉽게 할 수 있습니다.

     

    전체 코드는 https://github.com/BitzFlex/hello_web.git에서 받으실 수 있습니다.

     

Designed by Tistory.