Skip to content

Instantly share code, notes, and snippets.

@Bogdanp
Created June 25, 2016 20:58
Show Gist options
  • Save Bogdanp/15e0aafd9ad08c32563d1e01da17e312 to your computer and use it in GitHub Desktop.
Save Bogdanp/15e0aafd9ad08c32563d1e01da17e312 to your computer and use it in GitHub Desktop.
enum Status {
Todo,
Complete,
Deleted
}
record Unit {}
record Todo {
id Int
deadline DateTime
description String
status Status
}
fn getTodos() [Todo]
fn getTodo(id Int) Todo?
fn addTodo(deadline DateTime, description String) Todo
fn deleteTodo(id Int) Unit
package todos
import (
"encoding/json"
"errors"
"net/http"
)
type Status string
var (
StatusTodo Status = "Todo"
StatusComplete Status = "Complete"
StatusDeleted Status = "Deleted"
)
type Unit struct {
}
type Todo struct {
ID int `json:"id"`
Deadline float64 `json:"deadline"`
Description string `json:"description"`
Status Status `json:"status"`
}
type GetTodosRequest struct {
}
type GetTodoRequest struct {
ID int `json:"id"`
}
type AddTodoRequest struct {
Deadline float64 `json:"deadline"`
Description string `json:"description"`
}
type DeleteTodoRequest struct {
ID int `json:"id"`
}
type Todos struct {
getTodos func(*http.Request, GetTodosRequest) ([]Todo, error)
getTodo func(*http.Request, GetTodoRequest) (*Todo, error)
addTodo func(*http.Request, AddTodoRequest) (Todo, error)
deleteTodo func(*http.Request, DeleteTodoRequest) (Unit, error)
}
func (s Todos) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
var err error
var res interface{}
enc := json.NewEncoder(rw)
dec := json.NewDecoder(req.Body)
fn := req.URL.Query().Get("fn")
if req.Method != http.MethodPost {
err = errors.New("method not allowed")
} else if fn == "getTodos" {
var request GetTodosRequest
err = dec.Decode(&request)
if err == nil {
res, err = s.getTodos(req, request)
}
} else if fn == "getTodo" {
var request GetTodoRequest
err = dec.Decode(&request)
if err == nil {
res, err = s.getTodo(req, request)
}
} else if fn == "addTodo" {
var request AddTodoRequest
err = dec.Decode(&request)
if err == nil {
res, err = s.addTodo(req, request)
}
} else if fn == "deleteTodo" {
var request DeleteTodoRequest
err = dec.Decode(&request)
if err == nil {
res, err = s.deleteTodo(req, request)
}
} else {
err = errors.New("invalid function")
}
if err != nil {
rw.WriteHeader(http.StatusBadRequest)
err = enc.Encode(err.Error())
if err != nil {
panic(err)
}
} else {
rw.WriteHeader(http.StatusOK)
err = enc.Encode(res)
if err != nil {
panic(err)
}
}
}
func (s *Todos) HandleGetTodos(h func(*http.Request, GetTodosRequest) ([]Todo, error)) *Todos {
s.getTodos = h
return s
}
func (s *Todos) HandleGetTodo(h func(*http.Request, GetTodoRequest) (*Todo, error)) *Todos {
s.getTodo = h
return s
}
func (s *Todos) HandleAddTodo(h func(*http.Request, AddTodoRequest) (Todo, error)) *Todos {
s.addTodo = h
return s
}
func (s *Todos) HandleDeleteTodo(h func(*http.Request, DeleteTodoRequest) (Unit, error)) *Todos {
s.deleteTodo = h
return s
}
module Api.Todos exposing
( Status(..)
, ClientConfig
, Todo
, Unit
, addTodo
, defaultConfig
, deleteTodo
, getTodo
, getTodos
)
import Date exposing (Date)
import Dict exposing (Dict)
import HttpBuilder as HB
import Json.Decode as JD exposing (Decoder, (:=))
import Json.Decode.Extra exposing ((|:), date)
import Json.Encode as JE
import Task exposing (Task)
import Time exposing (Time)
type alias ClientConfig =
{ endpoint : String
, timeout : Time
, withAuth : HB.RequestBuilder -> HB.RequestBuilder
}
defaultConfig : String -> ClientConfig
defaultConfig endpoint =
ClientConfig endpoint (Time.second * 5) identity
decodeDate___ : Decoder Date
decodeDate___ =
JD.map Date.fromTime JD.float
encodeDate___ : Date -> JE.Value
encodeDate___ =
Date.toTime >> JE.float
encodeDict___ : (a -> JE.Value) -> Dict String a -> JE.Value
encodeDict___ f =
Dict.toList >> List.map (\(k, v) -> (k, f v)) >> JE.object
encodeMaybe___ : (a -> JE.Value) -> Maybe a -> JE.Value
encodeMaybe___ f =
Maybe.map f >> Maybe.withDefault JE.null
type Status
= StatusTodo
| StatusComplete
| StatusDeleted
encodeStatus__ : Status -> JE.Value
encodeStatus__ tag =
case tag of
StatusTodo -> JE.string "Todo"
StatusComplete -> JE.string "Complete"
StatusDeleted -> JE.string "Deleted"
decodeStatus__ : Decoder Status
decodeStatus__ =
let
dec s =
case s of
"Todo" -> Ok StatusTodo
"Complete" -> Ok StatusComplete
"Deleted" -> Ok StatusDeleted
_ -> Err "invalid Status"
in
JD.customDecoder JD.string dec
type alias Unit =
{
}
encodeUnit__ : Unit -> JE.Value
encodeUnit__ record =
JE.object
[
]
decodeUnit__ : Decoder Unit
decodeUnit__ =
JD.succeed Unit
type alias Todo =
{ id: Int
, deadline: Date
, description: String
, status: Status
}
encodeTodo__ : Todo -> JE.Value
encodeTodo__ record =
JE.object
[ ("id", JE.int record.id)
, ("deadline", encodeDate___ record.deadline)
, ("description", JE.string record.description)
, ("status", encodeStatus__ record.status)
]
decodeTodo__ : Decoder Todo
decodeTodo__ =
JD.succeed Todo
|: ("id" := JD.int)
|: ("deadline" := decodeDate___)
|: ("description" := JD.string)
|: ("status" := decodeStatus__)
getTodos : ClientConfig -> Task (HB.Error String) (HB.Response (List Todo))
getTodos config__ =
let
req =
JE.object
[
]
res =
(JD.list decodeTodo__)
in
HB.url config__.endpoint [("fn", "getTodos")]
|> HB.post
|> config__.withAuth
|> HB.withHeader "Content-type" "application/json"
|> HB.withJsonBody req
|> HB.withTimeout config__.timeout
|> HB.send (HB.jsonReader res) HB.stringReader
getTodo : ClientConfig -> Int -> Task (HB.Error String) (HB.Response (Maybe Todo))
getTodo config__ id =
let
req =
JE.object
[ ("id", JE.int id)
]
res =
(JD.maybe decodeTodo__)
in
HB.url config__.endpoint [("fn", "getTodo")]
|> HB.post
|> config__.withAuth
|> HB.withHeader "Content-type" "application/json"
|> HB.withJsonBody req
|> HB.withTimeout config__.timeout
|> HB.send (HB.jsonReader res) HB.stringReader
addTodo : ClientConfig -> Date -> String -> Task (HB.Error String) (HB.Response Todo)
addTodo config__ deadline description =
let
req =
JE.object
[ ("deadline", encodeDate___ deadline)
, ("description", JE.string description)
]
res =
decodeTodo__
in
HB.url config__.endpoint [("fn", "addTodo")]
|> HB.post
|> config__.withAuth
|> HB.withHeader "Content-type" "application/json"
|> HB.withJsonBody req
|> HB.withTimeout config__.timeout
|> HB.send (HB.jsonReader res) HB.stringReader
deleteTodo : ClientConfig -> Int -> Task (HB.Error String) (HB.Response Unit)
deleteTodo config__ id =
let
req =
JE.object
[ ("id", JE.int id)
]
res =
decodeUnit__
in
HB.url config__.endpoint [("fn", "deleteTodo")]
|> HB.post
|> config__.withAuth
|> HB.withHeader "Content-type" "application/json"
|> HB.withJsonBody req
|> HB.withTimeout config__.timeout
|> HB.send (HB.jsonReader res) HB.stringReader
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment