Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## api is the root of the cli for interacting with the rest api
Binary file added cmd/api/api
Binary file not shown.
90 changes: 90 additions & 0 deletions cmd/api/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//Package api is the root of the cli for our rest api and lives in cmd/api it is a convention in Golang to have "sub" binaries
//live inside a cmd package
package api

import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
)

//configure our flags using the builtin flags lib
var hostFlag = flag.String("host", "http://localhost:3001", "host is used to change the default host to call")

//declare some constants to use
const (
usage = "available commands: \n echo \n map \n slice "
ECHO = "echo"
MAP = "map"
SLICE = "slice"
)

func main() {
var err error
//set up some usage info
flag.Usage = func() {
fmt.Printf("Usage of %s:\n", os.Args[0])
fmt.Println(usage)
flag.PrintDefaults()
}
//ensure we parse our flags
flag.Parse()
if flag.NArg() == 0 {
flag.Usage()
os.Exit(1)
}
args := flag.Args() //cuts off things like ./api and any flags that are passed
cmd := args[0]
switch cmd {
case ECHO:
//configure the poster as the default http implementation and the writer as stdout
echo := echoCmd{poster: http.Post, writer: os.Stdout}
err = echo.Echo(args[1:]) //pass in all after echo
}
log.Fatalf("error running command %s : %s", cmd, err.Error())
}

//define a custom type that takes a poster and a writer this allows for cleaner simpler testing
type echoCmd struct {
poster func(string, string, io.Reader) (*http.Response, error)
writer io.Writer
}

//Echo calls the echo api in the web server writing the respose to the writer
func (cmd echoCmd) Echo(args []string) error {
if len(args) != 1 {
printAndExit("echo expects a message. echo <yourmessage>")
}
url := fmt.Sprintf("%s/api/echo", *hostFlag)
msg := map[string]string{
"message": args[0],
}
data, err := json.Marshal(msg)
if err != nil {
return fmt.Errorf("failed to prepare data for posting %s ", err.Error())
}
res, err := cmd.poster(url, "application/json", bytes.NewReader(data))
if err != nil {
return fmt.Errorf("failed to post to echo endpoint %s ", err.Error())
}
defer res.Body.Close()
resData, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to post to echo endpoint %s ", err.Error())
}
if _, err := cmd.writer.Write(resData); err != nil {
return fmt.Errorf("failed to write to out %s", err.Error())
}
return nil
}

func printAndExit(msg string) {
log.Println(msg)
os.Exit(0)
}
44 changes: 44 additions & 0 deletions cmd/api/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package api

import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/url"
"testing"
)

func TestEchoCmd(t *testing.T) {
mockPoster := func(api, contentType string, body io.Reader) (*http.Response, error) {
u, err := url.Parse(api)
if err != nil {
t.Fatal(err.Error())
}
if u.Path != "/api/echo" {
t.Fatal(err.Error())
}
resBody := `{"message":"test"}`
bodyRC := ioutil.NopCloser(bytes.NewReader([]byte(resBody)))
res := &http.Response{StatusCode: 200, Body: bodyRC}
return res, nil
}
var buffer bytes.Buffer
cmd := &echoCmd{poster: mockPoster, writer: &buffer}
args := []string{"test"}
if err := cmd.Echo(args); err != nil {
t.Fatal(err.Error)
}
message := map[string]string{}
if err := json.Unmarshal(buffer.Bytes(), &message); err != nil {
t.Fatal(err.Error())
}
if _, ok := message["message"]; !ok {
t.Fatal("expected their to be a message")
}
m := message["message"]
if m != "test" {
t.Fatal("expected the messag to be test")
}
}
38 changes: 38 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,48 @@ func Echo(res http.ResponseWriter, req *http.Request) {
}
}

func MapMe(rw http.ResponseWriter, req *http.Request) {
var (
jsonEncoder = json.NewEncoder(rw)
)

myMap := map[string]Message{
"message": Message{
Message: "hello map",
Stamp: time.Now().Unix(),
},
}

if err := jsonEncoder.Encode(myMap); err != nil {
rw.WriteHeader(http.StatusInternalServerError)
return
}
}

func SliceMe(rw http.ResponseWriter, req *http.Request) {
var (
jsonEncoder = json.NewEncoder(rw)
)

mySlice := []Message{
Message{
Message: "hello map",
Stamp: time.Now().Unix(),
},
}

if err := jsonEncoder.Encode(mySlice); err != nil {
rw.WriteHeader(http.StatusInternalServerError)
return
}
}

//Setup our simple router
func router() http.Handler {
//http.HandleFunc expects a func that takes a http.ResponseWriter and http.Request
http.HandleFunc("/api/echo", Echo)
http.HandleFunc("/api/map", MapMe)
http.HandleFunc("/api/slice", SliceMe)
return http.DefaultServeMux //this is a stdlib http.Handler
}

Expand Down