Go's standard library provides robust, built-in support for both creating HTTP servers and making HTTP requests as a client via the net/http package.
In python,python ask entire response body and put it in r.text
in go lang http.Get() only return headers but connection keeps open
The server has already sent (or is sending) the entire response over the TCP connection
and the data is kernel network buffers waiting to be read.
response,error := http.Get("https://api.restful-api.dev/objects/4")
if error != nil{
panic(error)
}
must run as it Schedules response.Body.Close() to run when main() exits
defer response.Body.Close()
defer refers to even if the code crash still execute it
it realeases the file descriptor so the go can reuse the tcp file descriptor connection to be returned to the connection pool for reuse (HTTP keep-alive). can also put response.Body.Close() at the end but connection may still be open if it crashes
reading response as text
io.ReadAll(resp.Body)
when you run this
This drains data from the kernel's network
buffers (where the server's response is already sitting) into our program's memory.
Copies bytes from kernel receive buffer
Into your program’s memory (userspace)
Returns number of bytes copied as a []byte slice.
No additional request is made to the server - we're just consuming data that was already transmitted.
b, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
fmt.Println(string(b))
reading response as json
"encoding/json" import is required to get all json funtionality
first we have to make a struct to store the json data in format its not like python which gives automatically its for men >:)
type PhoneRes struct {
ID string `json:"id"`
Name string `json:"name"`
Data Dat `json:"data"`
}
type Dat struct {
Price float64 `json:"price"` // number in JSON → float64 in Go
Color string `json:"color"`
}
this is for {"id":"4","name":"Apple iPhone 11, 64GB","data":{"price":389.99,"color":"Purple"}}
now we have to convert response.Body into this struct for doing that we do
json.NewDecoder(response.Body) -> json.NewDecoder() build upon io.ReadAll which drain the from buffers and then convert it into a struct
note:- if you run io.ReadAll(response.Body) before this it will drain the data and it will raise a error
to read from already drained data we use:
json.Unmarshal(data, &struct) data is the []bytes this reads from existing bytes and convert it into struct
all in action:
package main
import (
"fmt"
"io"
"net/http"
"encoding/json"
)
type PhoneRes struct {
ID string `json:"id"`
Name string `json:"name"`
Data Dat `json:"data"`
}
type Dat struct {
Price float64 `json:"price"` // number in JSON → float64 in Go
Color string `json:"color"`
}
func main(){
response,error := http.Get("https://api.restful-api.dev/objects/4")
if error != nil{
panic(error)
}
defer response.Body.Close()
b, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
fmt.Println(string(b))
var phone PhoneRes
json.NewDecoder()
decoder := json.NewDecoder(response.Body)
if err := decoder.Decode(&phone); err != nil {
fmt.Println("error decoding response body")
return
}
fmt.Println(phone.Data.Price)
derr := json.Unmarshal(b, &phone);
if derr != nil {
fmt.Println("error decoding response body")
return
}
fmt.Println(phone.Data.Price)
fmt.Println(response.Status)
fmt.Println(response.Header)
}
creating a request (GET)
we only looked at http.Get() but hold up!
we also have http.NewRequest(method,url,body) this give us more control to request. this create a request object
note:- it dosent open socket send request or anything we have to make http.Client for that
u can use req.Header.Set("User-Agent", "my-go-client/1.0") to set headers a
client := http.Client{}
response, err := client.Do(req)
if err != nil {
fmt.Println("error making request: ", err)
return
}
defer response.Body.close()
now make a client to actually send the request
request,error := http.NewRequest("GET","https://google.com",nil)
request.Header.Set("User-Agent", "my-go-client/1.0")
if error != nil{
fmt.Println("error bro")
return
}
client := &http.Client{}
resp, err := client.Do(request)
if err != nil{
fmt.Println("error bro 2")
return
}
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(b))
creating a request (POST)
main difference between get and post is post has body or payload which we send.
that can we crafted with:
json.Marshal(Struct)
like in get request we filled the struct with data now we convert that struct into a json
first create a json struct
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
now convert it into json
u := User{Name: "Alice", Age: 20}
body, err := json.Marshal(u)
if err != nil {
log.Fatal(err)
}
now send the rocket bytes.NewReader convert into buffer (bytes)
io.NewReader is just wraps the bytes its usually just
type Reader struct {
data []byte
index int
}
means if a func do_somthing(io.NewReader) he just can io.Read(data) it copies the litrally []byte (data[index:])
req, err := http.NewRequest("POST", "https://httpbin.org/post", bytes.NewReader(body))
full code:
u := User{Name: "Alice", Age: 20}
body, err := json.Marshal(u)
if err != nil {
log.Fatal(err)
}
req, err := http.NewRequest("POST", "https://httpbin.org/post", bytes.NewReader(body))
if err != nil {
log.Fatal(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
log.Println("Status:", resp.Status)
READING JSON DATA
first create a struct of json structure NOTE := VARIABLE NAME MUST START WITH CAPITAL LETTER
type Location struct {
Latitude float64 `json:"lat"`
Longitude float64 `json:"lon"`
}
now use json.Unmarshal(bodyBytes, &target) target is refrence of the object
request, error := http.NewRequest("GET", "http://ip-api.com/json/79.184.240.108?fields=192", nil)
if error != nil {
fmt.Println("error bro")
return
}
client := &http.Client{}
resp, errr := client.Do(request)
if errr != nil {
fmt.Println("error bro 2")
return
}
defer resp.Body.Close()
bodyBytes, err := io.ReadAll(resp.Body) // Read the entire body into a byte slice
if err != nil {
return
}
var target Location
json.Unmarshal(bodyBytes, &target)
fmt.Println(target.Longitude)
UDP
now we gonna do fun. udp used in streaming service .gaming where speed better than efficency.
two ways to send UDP 1. Unconnected UDP (Raw Packet Mode)
ListenUDP()
WriteTo()
ReadFrom()
```
You manually specify destination each time.
2.Connected UDP (Locked To One Remote)
DialUDP() Write() Read()
Socket is locked to one address.
package main
import ( "fmt" "net" // "math/rand/v2" )
func main() { address, err := net.ResolveUDPAddr("udp", "time.nist.gov:123") //setup address (returns ip) if err != nil { fmt.Println("error resolving") return } fmt.Println(address)
conn, errr := net.DialUDP("udp", nil, address) // setup dial a target connection somthing
if errr != nil {
fmt.Println("error conn")
return
}
fmt.Println(conn)
df, _ := conn.Write([]byte("wasap")) // write
fmt.Println(df)
buffer := make([]byte, 1024)
n, _, err := conn.ReadFromUDP(buffer) // read buffer
if err != nil {
// log.Printf("Receive error: %v", err)
return
}
fmt.Printf("Server says: %s\n", string(buffer[:n]))
}
```