- 
          
          Elixir Phoenix : Router와 ControllerElixir 프로그래밍 2019. 10. 8. 01:21Router는 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,_param) do 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,_param) do 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,_param) do 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,_param) do 가 두개 있는 것은, 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에서 받으실 수 있습니다. 'Elixir 프로그래밍' 카테고리의 다른 글Elixir Phoenix : Controller와 View(Template)간의 데이터 전달 : assigns (2) 2019.10.15 Elixir Phoenix : View와 Template (4) 2019.10.13 Elixir Phoenix Project 생성과 Project의 폴더 구조 (0) 2019.10.07 웹 서버와 Elixir Phoenix 기능 (0) 2019.10.01 Elixir 웹 프레임워크 Phoenix 들어가기 (0) 2019.10.01