Implement an HTTP server that has three routes and maintains a database of the world’s largest lakes.

  • The first route runs a handler postHandler which accepts a POST request with JSON-encoded lake information and posts it to the database.
    {
        "type": "post",
        "payload": {"id": "id00", "name": "Name of the lake", "area": 452001}
    }

     

  • The second route runs a handler deleteHandler which deletes the lake from the database by id. If the payload id is not present in the data set, the server returns a 404 response.
    {
        "type": "delete",
        "payload": "id00"
    }
  • The third route runs a handler getHandler which takes a lake from the database by id and returns it to the caller which prints the name and the area of the lakeIf the id is not found in the database, the server returns a string message “404 Not Found”. Otherwise, it returns the payload object corresponding to the id.
    {
        "type": "get",
        "payload": "id00"
    }

Implement the server which will be queried by the program and print the output to STDOUT.

 

Note:

The program uses these structs:

type Lake struct {
    Name string
    Area int32
}

type Action struct {
    Type string
    Payload string
}

 

The base URL is contained in the global variable address. Data is stored under the store variable which is the map[string] Lake.

Constraints

  • The total number of queries does not exceed 1000. 
  • The name and id strings consist of no more than 100 lowercase and uppercase English characters only. 
  • All the post ids are unique.

SOLUTION:

				
					package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

func postHandler(w http.ResponseWriter, req *http.Request) {
	var lake Lake
	err := json.NewDecoder(req.Body).Decode(&lake)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	store[lake.Id] = lake

	w.WriteHeader(http.StatusOK)
}

func deleteHandler(w http.ResponseWriter, req *http.Request) {
	id := req.URL.Query().Get("id")
	if id == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	_, ok := store[id]
	if !ok {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	delete(store, id)

	w.WriteHeader(http.StatusOK)
}

func getHandler(w http.ResponseWriter, req *http.Request) {
	id := req.URL.Query().Get("id")
	if id == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	lake, ok := store[id]
	if !ok {
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprintf(w, "404 Not Found")
		return
	}

	response, err := json.Marshal(lake)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(response)
}

func main() {
	reader := bufio.NewReaderSize(os.Stdin, 16*1024*1024)

	actionsCount, err := strconv.ParseInt(strings.TrimSpace(readLine(reader)), 10, 64)
	checkError(err)

	http.HandleFunc("/get", getHandler)
	http.HandleFunc("/post", postHandler)
	http.HandleFunc("/delete", deleteHandler)

	go http.ListenAndServe(portSuffix, nil)
	time.Sleep(100 * time.Millisecond)

	var actions []string

	for i := 0; i < int(actionsCount); i++ {
		actionsItem := readLine(reader)
		actions = append(actions, actionsItem)
	}

	for _, actionStr := range actions {
		var action Action
		err := json.Unmarshal([]byte(actionStr), &action)
		checkError(err)
		switch action.Type {
		case "post":
			_, err := http.Post(address+"/post", "application/json", strings.NewReader(action.Payload))
			checkError(err)
		case "delete":
			client := &http.Client{}
			req, err := http.NewRequest("DELETE", address+"/delete?id="+action.Payload, nil)
			checkError(err)
			resp, err := client.Do(req)
			checkError(err)
			if resp.StatusCode != http.StatusOK {
				fmt.Printf("%s\n", resp.Status)
				continue
			}
		case "get":
			resp, err := http.Get(address + "/get?id=" + action.Payload)
			checkError(err)
			if resp.StatusCode != http.StatusOK {
				fmt.Printf("%s\n", resp.Status)
				continue
			}
			var lake Lake
			err = json.NewDecoder(resp.Body).Decode(&lake)
			checkError(err)
			fmt.Printf("%s\n", lake.Name)
			fmt.Printf("%d\n", lake.Area)
		}
	}

	fmt.Printf("\n")
}

const portSuffix = ":3333"
var address = "http://127.0.0.1" + portSuffix

type Lake struct {
	Id   string `json:"id"`
	Name string `json:"name"`
	Area int32  `json:"area"`
}

type Action struct {
	Type    string
	Payload string
}

var store = map[string]Lake{}

func readLine(reader *bufio.Reader) string {
	str, _, err := reader.ReadLine()
	if err == io.EOF {
		return ""
	}

	return strings.TrimRight(string(str), "\r\n")
}

func checkError(err error) {
	if err != nil {
		panic(err)
	}
}