-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
3 changed files
with
267 additions
and
56 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
Example-Code/*.out | ||
|
||
codes | ||
Go/codes/go.mod |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
## JSON Marshaling and UnMarshaling in Go | ||
|
||
**Table of content :** | ||
|
||
1. What is JSON Marshaling and UnMarshaling ? | ||
2. encoding/json package | ||
3. JSON Encoding & Decoding. | ||
|
||
--- | ||
|
||
### What is JSON Marshaling and UnMarshaling ? | ||
|
||
1. **JSON Marshaling** : Converting a Go Data Structure like `struct`, `slice` or `map` into a valid JSON string. | ||
|
||
2. **JSON Unmarshaling** : Converting a valid JSON string into a Go Data Structure. | ||
|
||
Below given is a simple Go code which implements a struct `Message`. | ||
|
||
```go | ||
package main | ||
import "fmt" | ||
|
||
type Message struct { | ||
Sender string `json:"sender"` | ||
Receiver string `json:"receiver"` | ||
Text string `json:"text"` | ||
} | ||
|
||
func main() { | ||
m := Message{"amit", "sumit", "hello"} | ||
fmt.Println("Original :", m) | ||
} | ||
``` | ||
|
||
``` | ||
Original : {amit sumit hello} | ||
``` | ||
|
||
Let's encode the message `m` into a Valid JSON string. | ||
|
||
--- | ||
|
||
### `encoding/json` package : | ||
|
||
Package `encoding/json` implements encoding and decoding of JSON as defined in "**The JavaScript Object Notation (JSON) Data Interchange Format**" | ||
|
||
--- | ||
|
||
### **1. Marshaling :** | ||
|
||
To encode JSON data, we use the `Marshal` function by `encoding/json` package : | ||
|
||
```go | ||
func Marshal(v interface{}) ([]byte, error) | ||
``` | ||
|
||
Modifying our Messaging code: | ||
|
||
```go | ||
import ( | ||
"encoding/json", | ||
"fmt" | ||
) | ||
|
||
type Message struct { | ||
Sender string `json:"sender"` | ||
Receiver string `json:"receiver"` | ||
Text string `json:"text"` | ||
} | ||
|
||
func main(){ | ||
m := Message{"amit", "sumit", "hello"} | ||
fmt.Println("Original :", m) | ||
|
||
// encoding m into a JSON String | ||
b, err := json.Marshal(m) | ||
if err != nil { | ||
fmt.Println("error marshalling json") | ||
} | ||
fmt.Println("json encoded :", string(b)) | ||
} | ||
``` | ||
|
||
Above update will print : | ||
|
||
``` | ||
Original : {amit sumit hello} | ||
json encoded : {"sender":"amit", "receiver":"sumit", "text":"hello"} | ||
``` | ||
|
||
As we can observe, the Message m is now encoded into a JSON. | ||
|
||
Not stringfying the result `b` will print the encoded JSON as a slice of `byte` | ||
|
||
``` | ||
[123 34 115 101 110 100 101 114 34 58 34 97 109 105 116 34 44 34 114 101 99 101 105 118 101 114 34 58 34 115 117 109 105 116 34 44 34 116 101 120 116 34 58 34 104 101 108 108 111 34 125] | ||
``` | ||
|
||
--- | ||
|
||
### **2. Unmarshaling :** | ||
|
||
To decode JSON data, we use the `Unmarshal` function. | ||
|
||
```go | ||
func Unmarshal(data []byte, v interface{}) error | ||
``` | ||
|
||
Let's try to decode this Message m back to a `struct`. | ||
|
||
```go | ||
import ( | ||
"encoding/json", | ||
"fmt" | ||
) | ||
|
||
type Message struct { | ||
Sender string `json:"sender"` | ||
Receiver string `json:"receiver"` | ||
Text string `json:"text"` | ||
} | ||
|
||
func main(){ | ||
m := Message{"amit", "sumit", "hello"} | ||
fmt.Println("Original :", m) | ||
|
||
// encoding m into a JSON String | ||
b, err := json.Marshal(m) | ||
if err != nil { | ||
fmt.Println("error marshalling json") | ||
} | ||
fmt.Println("json encoded :", string(b)) | ||
|
||
// decoding back to struct | ||
err = json.Unmarshal([]byte(b), &m) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
fmt.Println("json decoded :", m) | ||
} | ||
``` | ||
|
||
--- | ||
|
||
### JSON Encoding & Decoding (yeah, it's different from Marshalling) | ||
|
||
`encoding/json` package provides few more Encoding & Decoding methods. | ||
|
||
### **1. NewEncoder :** | ||
|
||
- Creates an `Encoder` that writes JSON-encoded data to an `io.Writer` (file, network connection, etc). | ||
|
||
- Used for streaming encoding, where data might be produced incrementally. | ||
|
||
- Example: `encoder := json.NewEncoder(os.Stdout), encoder.Encode(myStruct)` | ||
|
||
### **2. NewDecoder :** | ||
|
||
- Creates a `Decoder` that reads JSON-encoded data from an `io.Reader` (file, network connection, etc). | ||
|
||
- Used for decoding streams of JSON data, where the entire data might not be available at once. | ||
|
||
- Example: `decoder := json.NewDecoder(res.Body), err := decoder.Decode(&myStruct)` | ||
|
||
**Key Differences:** | ||
|
||
- Whole Data vs. Streams: `Marshal` and `Unmarshal` operate on complete data, while `encoders`/`decoders` **handle streams of data.** | ||
|
||
- Under-the-Hood: `Marshal` often uses an `encoder` internally, and `Unmarshal` often uses a `decoder`. | ||
|
||
- Error Handling: `Decoders` can return `io.EOF` to signal the end of the stream, while `Unmarshal` typically returns other errors if parsing fails. | ||
|
||
**When to Use Which:** | ||
|
||
- Complete Data: Use `Marshal` and `Unmarshal` for one-time encoding/decoding of complete data structures. | ||
|
||
- Streaming Data: Use `encoders`/`decoders` for working with large or streaming JSON data to avoid loading everything into memory at once. | ||
|
||
- Multiple Objects: Use `decoders` to iterate over **multiple JSON objects** in a stream and process them individually. | ||
|
||
**Let's fetch some JSON from an api nd parse it to better understand Decoding:** | ||
|
||
To fetch JSON data, we'll use `https://hand-over.vercel.app/api/items` end-point which returns an array of items created at [handOver](https://hand-over.vercel.app). (yeah, that's my project) | ||
|
||
```go | ||
package main | ||
import ( | ||
"fmt" | ||
"net/http" | ||
"encoding/json" | ||
) | ||
|
||
func main(){ | ||
res, err := http.Get("https://hand-over.vercel.app/api/items") | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
defer res.Body.Close() | ||
var items []Item | ||
decoder := json.NewDecoder(res.Body) | ||
if err := decoder.Decode(&items); err != nil { | ||
fmt.Println("Error decoding JSON:", err) | ||
} else { | ||
fmt.Println(items) | ||
} | ||
} | ||
``` | ||
|
||
```go | ||
type Item struct { | ||
Id string `json:"id"` | ||
Description string `json:"description"` | ||
Price string `json:"price"` | ||
ImageUrl string `json:"imageUrl"` | ||
PublicId string `json:"publicId"` | ||
CatName string `json:"catName"` | ||
AuthorEmail string `json:"authorEmail"` | ||
CreatedAt string `json:"createdAt"` | ||
UpdatedAt string `json:"updatedAt"` | ||
Author Author `json:"author"` | ||
} | ||
|
||
type Author struct { | ||
Name string `json:"name"` | ||
Phone string `json:"phone"` | ||
} | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,74 +1,57 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
) | ||
import "fmt" | ||
|
||
func addEmailsToQueue(emails []string) chan string { | ||
emailsToSend := make(chan string, len(emails)) | ||
for _, email := range emails { | ||
emailsToSend <- email | ||
} | ||
return emailsToSend | ||
} | ||
|
||
func sendEmails(batchSize int, ch chan string) { | ||
for i := 0; i < batchSize; i++ { | ||
email := <-ch | ||
fmt.Println("Sending email:", email) | ||
} | ||
type Book struct { | ||
title string | ||
author string | ||
pages int | ||
isRead bool | ||
} | ||
|
||
func test(emails ...string) { | ||
fmt.Printf("Adding %v emails to queue...\n", len(emails)) | ||
type Shelf []Book | ||
|
||
ch := addEmailsToQueue(emails) | ||
|
||
fmt.Println("Sending emails...") | ||
sendEmails(len(emails), ch) | ||
fmt.Println("--------------------------") | ||
func addBookToShelf(b Book, s *Shelf) { | ||
*s = append(*s, b) | ||
} | ||
|
||
func fibonacci(n int) int { | ||
x, y := 0, 1 | ||
total := 0 | ||
for i := 0; i < n; i++ { | ||
total += x | ||
x, y = y, x+y | ||
func addBook(t, a string, p int, r bool) Book { | ||
book := Book{ | ||
title: t, author: a, pages: p, isRead: r, | ||
} | ||
return total | ||
return book | ||
} | ||
|
||
func splitAnySlice[T any](s []T) ([]T, []T) { | ||
mid := len(s) / 2 | ||
return s[:mid], s[mid:] | ||
func readBook(b *Book) { | ||
b.isRead = true | ||
} | ||
|
||
func main() { | ||
|
||
firstInts, secondInts := splitAnySlice([]int{0, 1, 2, 3}) | ||
fmt.Println(firstInts, secondInts) | ||
func printBook(b Book) { | ||
fmt.Printf("Title: %s by %s\nPages: %d\nisRead: %v", | ||
b.title, b.author, b.pages, b.isRead, | ||
) | ||
} | ||
|
||
fmt.Println("Buffered Channels: ") | ||
test("Hello John, tell Kathy I said hi", "Whazzup bruther") | ||
test("I find that hard to believe.", "When? I don't know if I can", "What time are you thinking?") | ||
test("She says hi!", "Yeah its tomorrow. So we're good.", "Cool see you then!", "Bye!") | ||
fmt.Println() | ||
func printShelf(s Shelf) { | ||
for i, book := range s { | ||
fmt.Printf("Book no: %d\n", i+1) | ||
printBook(book) | ||
fmt.Println() | ||
fmt.Println() | ||
} | ||
} | ||
|
||
fib := fibonacci(69) | ||
fmt.Print(fib) | ||
func main() { | ||
fmt.Println("============> Book Shelf <===========") | ||
var myShelf Shelf | ||
|
||
ticker := time.NewTicker(1000 * time.Millisecond) | ||
go func() { | ||
<-ticker.C | ||
fmt.Println("Tick at", time.Now()) | ||
}() | ||
book1 := addBook("Ramayana", "Valmiki", 200, false) | ||
addBookToShelf(book1, &myShelf) | ||
|
||
// Allow the ticker to run for 3 seconds | ||
time.Sleep(3 * time.Second) | ||
book2 := addBook("Can't Hurt Me", "David Goggins", 100, false) | ||
addBookToShelf(book2, &myShelf) | ||
|
||
// Stop the ticker after 3 seconds | ||
ticker.Stop() | ||
fmt.Println("Ticker stopped") | ||
readBook(&myShelf[0]) | ||
fmt.Println() | ||
printShelf(myShelf) | ||
} |