• Compojure

    • 시작하기
    • 라우팅하기
    • 라우팅 함수들 for 정적파일
  • #시작하기

    compojure는 clojure로 웹개발시에 빠르게 ring 핸들러를 생성하는 DSL을 제공해준다. ( compojure는 Ring을 기반으로 해서 작동한다 )

    compojure로 시작하기 위해서는 아래와 같이 leiningen 명령을 내리면 된다.

    lein new compojure hello-world

    저렇게 하면 leiningen이 알아서 compojure template을 다운로드 받아서 필요한 설정을 끝내논다.

    저렇게 한 다음에

    lein ring server

    를 실행해서 서버를 시작한다. 남는 포트 아무거나 하나 찾아서 화면에 띄워준다. 이 기능은 ring-serve라는 plugin을 통해서 제공되는 기능이다.

  • 라우팅하기

    compojure를 이용하면 ring handler를 명확하게 만들 수 있다.

    예를 틀면 아래처럼

    (GET "/user/:id" [id]
        (str "<h1>Hello user " id "</h1>"))
  • #Routing for 정적파일

    Compojure에서 라우팅에 유용한 3개의 함수를 추가로 제공해준다

    • files
    • not-found
    • resources
  • 기본 파트 설명

    • HTTP method
    • URI 매치
    • Request Destructuring
    • 요청처리
  • #Destructuring Syntax

    Compojure가 2가지 형태의 destructuring을 지원한다

    1. Clojure의 let과 같은 형태의 destructuring
    2. Compojure의 특화된 형태, request map에 있는 내용을 parsing하기 위해서 특수화된 것이다.
      • 쿼리와 폼 파라미터
      • url path의 일부분을 parsing하는 것

    1번 형태보다는 2번을 더 자주 쓸것으로 보인다.

  • 중첩 라우팅

    Routing을 중첩해서 사용하려면 context 매크로를 사용한다.
    구조적으로 관리하려면 이렇게 하는게 맞는 답이 아니겠는가?

    (defroutes api-routes
        (GET "/something" [] ... ))    ; matches /api/something
    
    (defroutes main-routes
        (context "/api" [] api-routes)
        other-routes)
  • #Routing for 정적파일 - 조금만 더 생각해보자

    Compojure의 compojure.route/ 네임 스페이스 아래에 있는 함수는 defroutes를 이용해서 라우팅 목록을 구성할 때 간편하게 사용할 수 있다.

    (defroutes app-routes
        (GET "/" [] "Hello World Thanks")
        (route/resources "/")
        (route/not-found "Not Found"))  

    위의 코드의 경우 리소스를 주면 클래스 path 상에 있는 리소스를 serving해준다. 기본값은 public이다.

  • HTTP method

    라우팅 핸들러를 compojure로 작성할 때는 첫번째로 http method를 넣는다.

    GET

    GET으로 들어오는 request는 여기 routing을 타고 들어가게 된다. 만약 match가 되지 않으면 nil이 돌려진다. ( 알듯이 nil은 곧 false를 의미한다 )

    지원하는 http method 목록은 아래와 같다

    • GET
    • POST
    • PUT
    • DELETE
    • HEAD
    • ANY - 모든지 매치시켜준다
  • URI 매치

    다음으로 나오는 부분은 uri 매치하는데 사용한다.

    "/user/:id"

    request의 url과 매치되는지 체크한다. 여기서 :id는 매치되어서 id 로컬value에 값을 binding시킨다. (이게 맞는 설명인가?)

    더 정교하게 매치하고 싶다면 저 id 파트에 대해서 따로 더 기술 할 수가 있다.
    이 때는 uri를 string으로 적지 않고 벡터로 적는다. 뻭떠로.

    ["/user/:id" id #"[0-9]+"]

    매치되지 않으면 nil이 돌아간다

  • Request Destructuring

    다음으로 나오는 곳에서 request map으로부터 필요한 정보를 뽑아오는 단계이다.

    [id]

    클로져의 destructuring form을 지원한다.

  • 요청처리

    마지막에 나오는 것이 실제로 내용을 처리하는 곳이다.
    리턴값은 지능적으로 처리가된다. 위에서는 문자열을 돌려주었는데 알아서 http response map으로 변경시켜버린다.

    {:status 200
     :headers {"Content-Type" "text/html; charset=utf-8" }
     :body "<h1>Hello user 1</h1>"}

    이 리턴값을 지능적으로 처리하는 것은 compojure에서 구현한 멀티메서드에 의해서 된다. ( 자세한 코드는 여기 https://github.com/weavejester/compojure/blob/master/src/compojure/response.clj )

    여기 마지막에 처리하는 곳을 custom type을 지원하게 하는 것으로 변경할 수가 있다.

  • Clojure Style Destructuring

    map이나 symbol등을 이용한다면 clojure style로 한다? (누가 정한거지? ㅋㅋㅋ )

    (GET "/:foo" {{foo :foo} :params}
       (str "Foo = " foo))

    여기서 :params에 있는 :foo를 참조해서 foo에 binding시켜버린다. (:params는 ring request map에 정의되어있다)

  • #Compojure Style Destructuring

    Clojure style은 타이핑을 많이해야한다. 그래서 compojure에서 특별한 형태의 destructuring 폼을 준비했다. 영리하게 벡터를 사용하면 compojure style로 간다고 판단한다.

    • map style은 Clojure style
    • vector style은 Compojure style

      (GET “/:foo” [foo]

        (str "Foo = " foo))
  • Compojure Style이 제공하는 첫째

    binding parameter이름을 똑같은 이름의 symbol로 match해준다. 예를 들어서 request map이 아래처럼 되었다.

    {:request-method :get
     :uri "/foobar"
     :headers {}
     :params {:x "foo", :y "bar", :z "baz", :w "qux"}}

    그리고 destructuring vector에다가 [x y z]라고 적으면 똑똑하신 compojure께서

    x -> "foo"
    y -> "bar"
    z -> "baz"

    로 바인딩을 시켜주신다.

  • Compojure Style이 제공하는 둘째

    특정 파라미터만 빼올 수 있을 뿐만 아니라 나머지 request map의 params는 &로 빼내오면 된다.

    [x y & z]
    x -> "foo"
    y -> "bar"
    z -> {:z "baz", :w "qux"}

    Clojure style과는 다르게 map을 돌려준다는 것이다. 빽터가 아니라 map이다.

  • Compojure Style이 제공하는 셋째

    전체 request map을 가져와야할 때는 :as를 사용한다.

    [x y :as r]
    
    x -> "foo"
    y -> "bar"
    r -> {:request-method :get
            :uri "/foobar"
            :headers {}
            :params {:x "foo" :y "bar" :z "baz" :w "qux" }

    만약 request map을 통째로 가져오는 것이 아니라 파라미터가 아닌 다른 값을 가져와야 하면, :as를 사용해서 할 수 있다.

    [x y :as {u :uri}]

    단순합니다.

  • #context

    API문서를 들쳐보면 context는 context아래 들어온 모든 routing에 대해서

    • 같은 path prefix
    • 같은 binding set

    을 같게 만들어준다

{"cards":[{"_id":"35a94b9af6dc6e5ed6000057","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":1,"parentId":null,"content":"# Compojure\n\n* 시작하기\n* 라우팅하기\n* 라우팅 함수들 for 정적파일 \n"},{"_id":"360349b4074cce8318000037","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":2,"parentId":null,"content":"#시작하기\n\ncompojure는 clojure로 웹개발시에 빠르게 ring 핸들러를 생성하는 DSL을 제공해준다. (* compojure는 Ring을 기반으로 해서 작동한다 *)\n\ncompojure로 시작하기 위해서는 아래와 같이 leiningen 명령을 내리면 된다.\n\n lein new compojure hello-world\n\n저렇게 하면 leiningen이 알아서 compojure template을 다운로드 받아서 필요한 설정을 끝내논다. \n\n저렇게 한 다음에 \n\n lein ring server\n\n를 실행해서 서버를 시작한다. 남는 포트 아무거나 하나 찾아서 화면에 띄워준다. 이 기능은 ring-serve라는 plugin을 통해서 제공되는 기능이다. "},{"_id":"36035395074cce8318000038","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":3,"parentId":null,"content":"# 라우팅하기\n\ncompojure를 이용하면 ring handler를 명확하게 만들 수 있다.\n\n예를 틀면 아래처럼\n\n (GET \"/user/:id\" [id]\n (str \"<h1>Hello user \" id \"</h1>\"))\n"},{"_id":"36035720074cce8318000039","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":1,"parentId":"36035395074cce8318000038","content":"# 기본 파트 설명\n\n* HTTP method\n* URI 매치\n* Request Destructuring\n* 요청처리"},{"_id":"3603b31a074cce831800003a","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":1,"parentId":"36035720074cce8318000039","content":"# HTTP method\n\n라우팅 핸들러를 compojure로 작성할 때는 첫번째로 http method를 넣는다.\n\n GET\n\nGET으로 들어오는 request는 여기 routing을 타고 들어가게 된다. 만약 match가 되지 않으면 nil이 돌려진다. (* 알듯이 nil은 곧 false를 의미한다 *)\n\n지원하는 http method 목록은 아래와 같다\n\n* `GET`\n* `POST`\n* `PUT`\n* `DELETE`\n* `HEAD`\n* `ANY` - 모든지 매치시켜준다\n\n\n"},{"_id":"3603bbac074cce831800003b","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":2,"parentId":"36035720074cce8318000039","content":"# URI 매치\n\n다음으로 나오는 부분은 uri 매치하는데 사용한다. \n\n \"/user/:id\"\n\nrequest의 url과 매치되는지 체크한다. 여기서 `:id`는 매치되어서 id 로컬value에 값을 binding시킨다. (이게 맞는 설명인가?)\n\n더 정교하게 매치하고 싶다면 저 id 파트에 대해서 따로 더 기술 할 수가 있다.\n이 때는 uri를 string으로 적지 않고 벡터로 적는다. 뻭떠로.\n\n [\"/user/:id\" id #\"[0-9]+\"]\n\n매치되지 않으면 nil이 돌아간다\n"},{"_id":"3603c41e074cce831800003c","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":3,"parentId":"36035720074cce8318000039","content":"# Request Destructuring\n\n다음으로 나오는 곳에서 request map으로부터 필요한 정보를 뽑아오는 단계이다.\n\n [id]\n\n클로져의 destructuring form을 지원한다. \n"},{"_id":"3603c91d074cce831800003e","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":4,"parentId":"36035720074cce8318000039","content":"# 요청처리\n\n마지막에 나오는 것이 실제로 내용을 처리하는 곳이다.\n리턴값은 지능적으로 처리가된다. 위에서는 문자열을 돌려주었는데 알아서 http response map으로 변경시켜버린다.\n\n {:status 200\n :headers {\"Content-Type\" \"text/html; charset=utf-8\" }\n :body \"<h1>Hello user 1</h1>\"}\n\n이 리턴값을 지능적으로 처리하는 것은 compojure에서 구현한 멀티메서드에 의해서 된다. (* 자세한 코드는 여기 https://github.com/weavejester/compojure/blob/master/src/compojure/response.clj *)\n\n여기 마지막에 처리하는 곳을 custom type을 지원하게 하는 것으로 변경할 수가 있다."},{"_id":"3603d51f074cce831800003f","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":2,"parentId":"36035395074cce8318000038","content":"#Destructuring Syntax\n\nCompojure가 2가지 형태의 destructuring을 지원한다\n\n1. Clojure의 let과 같은 형태의 destructuring\n2. Compojure의 특화된 형태, request map에 있는 내용을 parsing하기 위해서 특수화된 것이다.\n * 쿼리와 폼 파라미터\n * url path의 일부분을 parsing하는 것\n\n1번 형태보다는 2번을 더 자주 쓸것으로 보인다.\n\n"},{"_id":"3604a0e5074cce8318000040","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":1,"parentId":"3603d51f074cce831800003f","content":"# Clojure Style Destructuring\nmap이나 symbol등을 이용한다면 clojure style로 한다? (*누가 정한거지? ㅋㅋㅋ *)\n\n (GET \"/:foo\" {{foo :foo} :params}\n (str \"Foo = \" foo))\n\n여기서 `:params`에 있는 `:foo`를 참조해서 foo에 binding시켜버린다. (`:params`는 ring request map에 정의되어있다)\n\n"},{"_id":"3604bc23074cce8318000041","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":2,"parentId":"3603d51f074cce831800003f","content":"#Compojure Style Destructuring\n\nClojure style은 타이핑을 많이해야한다. 그래서 compojure에서 특별한 형태의 destructuring 폼을 준비했다. 영리하게 벡터를 사용하면 compojure style로 간다고 판단한다.\n\n* map style은 Clojure style\n* vector style은 Compojure style\n\n (GET \"/:foo\" [foo] \n (str \"Foo = \" foo))\n\n"},{"_id":"3604cb6f074cce8318000042","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":3,"parentId":"3603d51f074cce831800003f","content":"# Compojure Style이 제공하는 **첫째**\n\nbinding parameter이름을 똑같은 이름의 symbol로 match해준다. 예를 들어서 request map이 아래처럼 되었다.\n\n\n {:request-method :get\n :uri \"/foobar\"\n :headers {}\n :params {:x \"foo\", :y \"bar\", :z \"baz\", :w \"qux\"}}\n\n그리고 destructuring vector에다가 [x y z]라고 적으면 똑똑하신 compojure께서\n \n x -> \"foo\"\n y -> \"bar\"\n z -> \"baz\"\n\n로 바인딩을 시켜주신다.\n"},{"_id":"3604cc7f074cce8318000043","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":4,"parentId":"3603d51f074cce831800003f","content":"# Compojure Style이 제공하는 **둘째**\n\n특정 파라미터만 빼올 수 있을 뿐만 아니라 나머지 request map의 params는 &로 빼내오면 된다.\n\n [x y & z]\n x -> \"foo\"\n y -> \"bar\"\n z -> {:z \"baz\", :w \"qux\"}\n\nClojure style과는 다르게 map을 돌려준다는 것이다. 빽터가 아니라 map이다."},{"_id":"3604d247074cce8318000044","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":5,"parentId":"3603d51f074cce831800003f","content":"# Compojure Style이 제공하는 셋째\n\n전체 request map을 가져와야할 때는 `:as`를 사용한다.\n\n [x y :as r]\n \n x -> \"foo\"\n y -> \"bar\"\n r -> {:request-method :get\n :uri \"/foobar\"\n :headers {}\n :params {:x \"foo\" :y \"bar\" :z \"baz\" :w \"qux\" }\n\n\n만약 request map을 통째로 가져오는 것이 아니라 파라미터가 아닌 다른 값을 가져와야 하면, :as를 사용해서 할 수 있다.\n\n [x y :as {u :uri}]\n\n단순합니다. "},{"_id":"360530a8074cce8318000046","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":3,"parentId":"36035395074cce8318000038","content":"# 중첩 라우팅\n\nRouting을 중첩해서 사용하려면 context 매크로를 사용한다.\n구조적으로 관리하려면 이렇게 하는게 맞는 답이 아니겠는가?\n\n (defroutes api-routes\n (GET \"/something\" [] ... )) ; matches /api/something\n \n (defroutes main-routes\n (context \"/api\" [] api-routes)\n other-routes)\n\n"},{"_id":"36055a7a074cce8318000048","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":1,"parentId":"360530a8074cce8318000046","content":"#context\n\nAPI문서를 들쳐보면 context는 context아래 들어온 모든 routing에 대해서\n* 같은 path prefix\n* 같은 binding set\n\n을 같게 만들어준다\n"},{"_id":"360562d8074cce8318000049","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":4,"parentId":null,"content":"#Routing for 정적파일\n\nCompojure에서 라우팅에 유용한 3개의 함수를 추가로 제공해준다\n* files\n* not-found\n* resources\n"},{"_id":"360567b7074cce831800004a","treeId":"35a94b84f6dc6e5ed6000054","seq":1,"position":1,"parentId":"360562d8074cce8318000049","content":"#Routing for 정적파일 - 조금만 더 생각해보자\n\nCompojure의 compojure.route/ 네임 스페이스 아래에 있는 함수는 defroutes를 이용해서 라우팅 목록을 구성할 때 간편하게 사용할 수 있다.\n\n (defroutes app-routes\n (GET \"/\" [] \"Hello World Thanks\")\n (route/resources \"/\")\n (route/not-found \"Not Found\")) \n\n위의 코드의 경우 리소스를 주면 클래스 path 상에 있는 리소스를 serving해준다. 기본값은 public이다.\n\n\n\n\n\n"}],"tree":{"_id":"35a94b84f6dc6e5ed6000054","name":"Compojure - Clojure","publicUrl":"compojure-clojure"}}