Json, in a jiffy!

Working with json in Erlang has vastly improved since the last time I looked at it, particularly with the addition of maps to the language (in R17).

-module(foo_handler).

-export([init/3]).
-export([allowed_methods/2, content_types_accepted/2]).
-export([foo/2]).

init(_Transport, _Req, []) ->
    {upgrade, protocol, cowboy_rest}.

allowed_methods(Req, State) ->
    {[<<"POST">>], Req, State}.

content_types_accepted(Req, State) ->
    {[
        {<<"application/json">>, foo}
    ], Req, State}.

foo(Req, State) ->
    {ok, Body, Req1} = cowboy_req:body(Req),
    Json = jiffy:decode(Body, [return_maps]),
    Bar = maps:get(<<"bar">>, Json),
    {ok, Res} = do_something(Bar),
    Body = jiffy:encode(#{result => Res}),
    {true, cowboy_req:set_resp_body(Body, Req1), State}.

A generic json handler in Go

One of the things I really like about Go is the way it encourages you to build up behaviour using composition. For example, I was writing handlers that return a response object as json; it’s very simple to extract the duplicated code into a generic handler:

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

type ResponseGenerator interface {
	GetResponse(r *http.Request) (interface{}, error)
}

type JsonHandler struct {
	log *log.Logger
	rg  ResponseGenerator
}

func (h *JsonHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	response, err := h.rg.GetResponse(r)
	if err != nil {
		h.log.Printf("ERROR: %v\n", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	b, err := json.Marshal(response)
	if err != nil {
		h.log.Printf("ERROR: %v\n", err)
		http.Error(w, "Unexpected error", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(b)
}