Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON #41

Merged
merged 3 commits into from
Feb 2, 2024
Merged

JSON #41

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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Example-Code/*.out

codes
Go/codes/go.mod
228 changes: 228 additions & 0 deletions Go/Basics/11-json.md
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"`
}
```
93 changes: 38 additions & 55 deletions Go/codes/temp.go
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)
}