LoginSignup
0

More than 3 years have passed since last update.

herokuのclojure-getting-startedでJSONを返す

Posted at

herokuでclojure appを作る

公式のGetting Started on Heroku with Clojureに従う。 英語しんどい。。。しんどい。。。

ローカルで動かす

別に git push heroku masterでherokuに上げなくても、ローカルで試せる。

これも公式が説明してくれる。 英語に慣れてないので見つけにくい
Heroku Dev Center - Getting Started on Heroku with Clojure: Run the app locally

僕はspacemacsを使っていたので、 cider-jack-inでreplを開いてから公式のように (require 'clojure-getting-started.web) => (def server (clojure-getting-started.web/-main))した。
ファイルを書き換えてサーバに反映したいときは Space e bでバッファごと評価し直すといけた。

herokuに送り込むのも、なんかmagitでcommitした後に P e heroku/masterって選んでいったらできた。なにもわからない。

JSONを返す

公式のサンプルコードでは、プレーンテキストだけを返す簡単な構成となっている(404とかはhtmlを返している模様?)

JSONも返したい。 正直なにもわからない

コード

試行錯誤の末こうなった。 clojure-getting-startedディレクトリ下で project.cljと src/clojure_getting_started/web.cljの2ファイルを書き換える。

/project.clj
(defproject clojure-getting-started "1.0.0-SNAPSHOT"
  :description "Demo Clojure web app"
  :url "http://clojure-getting-started.herokuapp.com"
  :license {:name "Eclipse Public License v1.0"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [compojure "1.6.1"]
                 [ring/ring-jetty-adapter "1.7.1"]
                 [ring/ring-json "0.5.0"] ; JSONを扱うために追加
                 [environ "1.1.0"]]
  :min-lein-version "2.0.0"
  :plugins [[environ/environ.lein "0.3.1"]]
  :hooks [environ.leiningen.hooks]
  :uberjar-name "clojure-getting-started-standalone.jar"
  :profiles {:production {:env {:production true}}})
/src/clojure_getting_started/web.clj
(ns clojure-getting-started.web
  (:require [compojure.core :refer [defroutes GET PUT POST DELETE ANY]]
            [compojure.handler :refer [site]]
            [compojure.route :as route]
            [clojure.java.io :as io]
            [ring.adapter.jetty :as jetty]
            [ring.middleware.json :refer [wrap-json-response]]
            [environ.core :refer [env]]))

(defn splash []
  {:status 200
   :headers {"Content-Type" "text/plain"}
   :body "Hello from Heroku"})

(defn my-json-response []
  {:status 200
   :headers {"Content-Type" "application/json;charset=utf-8"}
   :body {:name "v2okimochi"
          :version 2
          :state "( '・ω・`)"}})

(defroutes app
  (GET "/" []
       (splash))
  (GET "/please-json" []
       (my-json-response)) ; JSONを返す場合
  (ANY "*" []
       (route/not-found (slurp (io/resource "404.html")))))

(defn -main [& [port]]
  (let [port (Integer. (or port (env :port) 5000))]
    (jetty/run-jetty (-> (site app)
                         (wrap-json-response))
                     {:port port :join? false}))) ; JSONを返せる実装

;; For interactive development:
;; (.stop server)
;; (def server (-main))

差分

増えたところと減ったところ。インデントはゆるして。

/project.clj
(defproject clojure-getting-started "1.0.0-SNAPSHOT"
  :description "Demo Clojure web app"
  :url "http://clojure-getting-started.herokuapp.com"
  :license {:name "Eclipse Public License v1.0"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [compojure "1.6.1"]
                 [ring/ring-jetty-adapter "1.7.1"]
+                [ring/ring-json "0.5.0"] ; JSONを扱うために追加
                 [environ "1.1.0"]]
  :min-lein-version "2.0.0"
  :plugins [[environ/environ.lein "0.3.1"]]
  :hooks [environ.leiningen.hooks]
  :uberjar-name "clojure-getting-started-standalone.jar"
  :profiles {:production {:env {:production true}}})
/src/clojure_getting_started/web.clj
(ns clojure-getting-started.web
  (:require [compojure.core :refer [defroutes GET PUT POST DELETE ANY]]
            [compojure.handler :refer [site]]
            [compojure.route :as route]
            [clojure.java.io :as io]
            [ring.adapter.jetty :as jetty]
+           [ring.middleware.json :refer [wrap-json-response]]
            [environ.core :refer [env]]))

(defn splash []
  {:status 200
   :headers {"Content-Type" "text/plain"}
   :body "Hello from Heroku"})

+ (defn my-json-response []
+   {:status 200
+    :headers {"Content-Type" "application/json;charset=utf-8"}
+    :body {:name "v2okimochi"
+           :version 2
+           :state "( '・ω・`)"}})

(defroutes app
  (GET "/" []
       (splash))
+ (GET "/please-json" []
+      (my-json-response)) ; JSONを返す場合
  (ANY "*" []
       (route/not-found (slurp (io/resource "404.html")))))

(defn -main [& [port]]
  (let [port (Integer. (or port (env :port) 5000))]
-   (jetty/run-jetty (site #'app) {:port port :join? false}) ; サンプルでの実装
+   (jetty/run-jetty (-> (site app)
+                        (wrap-json-response))
+                    {:port port :join? false}))) ; JSONを返せる実装

;; For interactive development:
;; (.stop server)
;; (def server (-main))

実際に叩くとこう

ローカルならlocalhost:5000/で繋がる。ルートならサンプル通りのテキストが返る。
新たに作った localhost:5000/please-jsonにアクセスすると、ちゃんとJSONを返してくれる。

ちなみにこういうAPIサーバっぽいのに接続するときにはpostman使うのおすすめ。結果がわかりやすいしヘッダ情報とかも見られる。

{
    "name": "v2okimochi",
    "version": 2,
    "state": "( '・ω・`)"
}

なおコードにあった :headersは無くてもよろしくやってくれた。でも指定すると安心。

JSON返すだけで (調べるのが) たいへん。メモしとかないと書いてるそばからもう既に忘れている。

まとめ

  • herokuのclojure-getting-startedコードを拡張してJSON返せるようになった
  • なんでこうなるのかわかりてえなあ

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
0