Created
June 25, 2016 20:58
-
-
Save Bogdanp/15e0aafd9ad08c32563d1e01da17e312 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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