Create CRUD Apps with http/net Golang without database

This article just have a purpose to show how to create CRUD (Create, Read, Update & Delete) Apps just using http/net.

First step we need to create project directory.

mkdir golang-basic-http # create directory project
cd golang-basi…


This content originally appeared on DEV Community and was authored by Adiatma Kamarudin

This article just have a purpose to show how to create CRUD (Create, Read, Update & Delete) Apps just using http/net.

First step we need to create project directory.

mkdir golang-basic-http # create directory project
cd golang-basic-http # go to project
go mod init golang-basic-http # initialize go module inside the project

Next, please create file main.go, with touch main.go inside the project directory.

package main

import "fmt"

func main() {
   fmt.Println("Hello world")
}

Than, execute the main.go.

go run main.go
Hello world # the result

Next, we need to import http/net and create the http server.

package main

import (
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
        rw.Write([]byte("Hello World"))
    })

    log.Fatal(http.ListenAndServe(":8000", nil))
}

Ok, http.HandleFunc have 2 parameters, to fill with route path and handler, path describe the route, and handler is a function, and the function have 2 parameters http.ResponseWriter to write the output, and http.Request to catch the request from http.

Next, inside handler we need to create response Hello World if user access the path.

// rw is http.ResponseWriter
rw.Write([]byte("Hello world"))

And to listens on the TCP network we using http.ListenAndServer.

http.ListenAndServer(":8000", nil)

http.ListenAndServer have 2 parameters, first parameter fill with the port address, and next with route config, because we don't use router configuration, for this time, second parameter in http.ListenAndServer we can fill with nil.

If you access the http with port 8000 using curl in the terminal.

curl -i http://localhost:8000

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 04:58:38 GMT
Content-Length: 11
Content-Type: text/plain; charset=utf-8

Hello world%

Yes, congratulations.

Next, we need create methods GET, POST, DELETE, and PUT inside the handler.

To get methods, we need access r in http.Request.

 switch r.Method {
    case "GET":
      rw.Write([]byte("GET/ Hello World"))
    case "POST":
      rw.Write([]byte("POST/ Hello World"))
 }

Try to access GET

curl -i http://localhost:8000

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 05:26:01 GMT
Content-Length: 16
Content-Type: text/plain; charset=utf-8

GET/ Hello World%

Next, try to access POST

curl -i -X POST http://localhost:8000

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 05:25:44 GMT
Content-Length: 17
Content-Type: text/plain; charset=utf-8

POST/ Hello World%

Ok, next we need to define data, example Todo with have Task and ID.

type Todo struct {
    ID   int
    Task string
}

func main() {
...

...and, define collection of Todo, in todos variable.

type Todo struct {
    ID   int
    Task string
}

var todos []Todo

func main() {
...

...next we need to access todos, inside handler.

switch r.Method {
case "GET":
  json.NewEncoder(rw).Encode(todos)
...

json.NewEncoder(rw).Encode(todos) convert todos and encode to json format as the result.

Save, and next run go run main.go

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 05:54:23 GMT
Content-Length: 5
Content-Type: text/plain; charset=utf-8

null

Oops, the result is null cause todos is empty, we need to create post to fill todos with new value.

case "POST":
   // create variable to save todo
   var todo Todo
   // decode `r.Body` `r *http.Request` to get data from request
   // decode the result to todo
   json.NewDecoder(r.Body).Decode(&todo)
   // append new todo in todos
   todos = append(todos, todo)
   // finally, encode again create the resutl with json format
   json.NewEncoder(rw).Encode(todo)
}

...next, save and try again, we need to access POST to save new value.

curl -i -X POST -d '{"ID": 1, "Task": "Coding..."}' http://localhost:8000

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 06:01:37 GMT
Content-Length: 28
Content-Type: text/plain; charset=utf-8

{"ID":1,"Task":"Coding..."}

...next, access GET.

curl -i http://localhost:8000

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 06:01:59 GMT
Content-Length: 30
Content-Type: text/plain; charset=utf-8

[{"ID":1,"Task":"Coding..."}]

Next, we need add method DELETE to remove todo base on the ID in todo.

case "DELETE":
  // http/net not support path variable like this `/:id`
  // and to handle it, we using `r.URL.Query` to get the query url
  // http://localhost:8000?id=1
  query := r.URL.Query()
  // id result have a type string
  // we need `strconv.Atoi` to convert string into int
  id, _ := strconv.Atoi(query.Get("id"))

  // next we need to loop todos, and match the id with todo.ID
  for index, todo := range todos {
     if todo.ID == id {
        // splice and replace the todo
        todos = append(todos[:index], todos[index+1:]...)
        rw.Write([]byte("Success to deleted todo"))
     }
  }

...save, and run again

curl -i http://localhost:8000

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 06:25:21 GMT
Content-Length: 30
Content-Type: text/plain; charset=utf-8

[{"ID":1,"Task":"Coding..."}]
curl -i -X DELETE http://localhost:8000\?id\=1

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 06:26:30 GMT
Content-Length: 23
Content-Type: text/plain; charset=utf-8

Success to deleted todo%
curl -i http://localhost:8000

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 06:27:00 GMT
Content-Length: 3
Content-Type: text/plain; charset=utf-8

[]
 case "PUT":
    query := r.URL.Query()
    id, _ := strconv.Atoi(query.Get("id"))

    for index, todo := range todos {
       json.NewDecoder(r.Body).Decode(&todo)

       if todo.ID == id {
          todos[index].ID = todo.ID
          todos[index].Task = todo.Task

          rw.Write([]byte("Success to update todo"))
       }
    }
}

...yup, save, and run again

curl -i -X POST -d '{"ID": 1, "Task": "Coding..."}' http://localhost:8000

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 06:33:35 GMT
Content-Length: 28
Content-Type: text/plain; charset=utf-8

{"ID":1,"Task":"Coding..."}

---
curl -i http://localhost:8000

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 06:34:10 GMT
Content-Length: 30
Content-Type: text/plain; charset=utf-8

[{"ID":1,"Task":"Coding..."}]

...update data

curl -i -X PUT -d '{"ID": 1, "Task": "Bobo siang"}' http://localhost:8000\?id\=1

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 06:35:32 GMT
Content-Length: 22
Content-Type: text/plain; charset=utf-8

Success to update todo%

---
curl -i http://localhost:8000

HTTP/1.1 200 OK
Date: Sun, 22 Aug 2021 06:39:24 GMT
Content-Length: 35
Content-Type: text/plain; charset=utf-8

[{"ID": 1, "Task": "Bobo siang"}]

Yes, congratulations!, and next we need to custom header, and need a little refactor.

package main

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

type Todo struct {
    ID   int
    Task string
}

var todos []Todo

func main() {
    http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
        rw.Header().Add("Content-Type", "application/json")
        rw.Header().Add("Access-Control-Allow-Origin", "*")

        query := r.URL.Query()
        id, _ := strconv.Atoi(query.Get("id"))

        switch r.Method {
        case "GET":
            rw.WriteHeader(http.StatusOK)
            json.NewEncoder(rw).Encode(todos)
        case "POST":
            var todo Todo
            json.NewDecoder(r.Body).Decode(&todo)
            todos = append(todos, todo)
            rw.WriteHeader(http.StatusOK)
            json.NewEncoder(rw).Encode(todo)
        case "DELETE":
            for index, todo := range todos {
                if todo.ID == id {
                    todos = append(todos[:index], todos[index+1:]...)
                    rw.WriteHeader(http.StatusOK)
                    rw.Write([]byte(`{"message": "Success to delete todo"}`))
                }
            }
        case "PUT":
            for index, todo := range todos {
                if todo.ID == id {
                    json.NewDecoder(r.Body).Decode(&todo)
                    todos[index].ID = todo.ID
                    todos[index].Task = todo.Task
                    rw.WriteHeader(http.StatusOK)
                    rw.Write([]byte(`{"message": "Success to update todo"}`))
                }
            }
        }
    })

    log.Fatal(http.ListenAndServe(":8000", nil))
}
curl http://localhost:8000 -v

*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Content-Type: application/json
< Date: Sun, 22 Aug 2021 06:54:01 GMT
< Content-Length: 5
<
null
* Connection #0 to host localhost left intact
* Closing connection 0

Yes, hopefully you can learn something with this basic article about http server in golang.


This content originally appeared on DEV Community and was authored by Adiatma Kamarudin


Print Share Comment Cite Upload Translate Updates
APA

Adiatma Kamarudin | Sciencx (2021-08-22T06:58:48+00:00) Create CRUD Apps with http/net Golang without database. Retrieved from https://www.scien.cx/2021/08/22/create-crud-apps-with-http-net-golang-without-database/

MLA
" » Create CRUD Apps with http/net Golang without database." Adiatma Kamarudin | Sciencx - Sunday August 22, 2021, https://www.scien.cx/2021/08/22/create-crud-apps-with-http-net-golang-without-database/
HARVARD
Adiatma Kamarudin | Sciencx Sunday August 22, 2021 » Create CRUD Apps with http/net Golang without database., viewed ,<https://www.scien.cx/2021/08/22/create-crud-apps-with-http-net-golang-without-database/>
VANCOUVER
Adiatma Kamarudin | Sciencx - » Create CRUD Apps with http/net Golang without database. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/08/22/create-crud-apps-with-http-net-golang-without-database/
CHICAGO
" » Create CRUD Apps with http/net Golang without database." Adiatma Kamarudin | Sciencx - Accessed . https://www.scien.cx/2021/08/22/create-crud-apps-with-http-net-golang-without-database/
IEEE
" » Create CRUD Apps with http/net Golang without database." Adiatma Kamarudin | Sciencx [Online]. Available: https://www.scien.cx/2021/08/22/create-crud-apps-with-http-net-golang-without-database/. [Accessed: ]
rf:citation
» Create CRUD Apps with http/net Golang without database | Adiatma Kamarudin | Sciencx | https://www.scien.cx/2021/08/22/create-crud-apps-with-http-net-golang-without-database/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.