mirror of
https://github.com/foomo/foomo-docs.git
synced 2025-10-16 12:35:40 +00:00
feat: Add backend go examples
This commit is contained in:
parent
776430dfec
commit
30ad429b9b
0
foomo/docs/backend/go-by-example/channels.mdx
Normal file
0
foomo/docs/backend/go-by-example/channels.mdx
Normal file
1
foomo/docs/backend/go-by-example/context.mdx
Normal file
1
foomo/docs/backend/go-by-example/context.mdx
Normal file
@ -0,0 +1 @@
|
||||
https://gobyexample.com/context
|
||||
71
foomo/docs/backend/go-by-example/defer.mdx
Normal file
71
foomo/docs/backend/go-by-example/defer.mdx
Normal file
@ -0,0 +1,71 @@
|
||||
---
|
||||
title: Defer
|
||||
sidebar_position: 1
|
||||
tags:
|
||||
- Go Basics
|
||||
---
|
||||
# Defer
|
||||
|
||||
In a normal Go application, control flows from the top to the bottom of any function that we call (this is if you don't use branching or looping).
|
||||
Through introducing ```defer``` we can execute the statement passed to it at the end of the function just before it returns. To demonstrate:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("first")
|
||||
fmt.Println("second")
|
||||
fmt.Println("third")
|
||||
}
|
||||
```
|
||||
If you copy the above code and execute it it will print 'first', 'second' and then 'third'. Now if we introduce ```defer``` to this function we see the order in which our statements are printed change.
|
||||
|
||||
```go
|
||||
func main() {
|
||||
fmt.Println("first")
|
||||
defer fmt.Println("second")
|
||||
fmt.Println("third")
|
||||
}
|
||||
```
|
||||
Executing this function will print: 'first', 'third' and then 'second'. This is because the statement that follows after the ```defer``` keyword is executed at the end of function we are calling, just before it returns.
|
||||
When it goes through this function if will print 'first', then it will recognise it has a defer function to call, it will print 'third' and then when it exits the function, it will check if there are any defer functions to call and if so it will call them.
|
||||
Which in our case is the print function that prints 'second'.
|
||||
What would happen if we add the defer keyword before each of our prints?
|
||||
```go
|
||||
func main() {
|
||||
defer fmt.Println("first")
|
||||
defer fmt.Println("second")
|
||||
defer fmt.Println("third")
|
||||
}
|
||||
```
|
||||
This results into 'third' being printed first, followed by 'second' and then 'first'. This is because the defer keyword executes in last-in-first-out (LIFO) order.
|
||||
This makes sense because defer is usually used to close out resources, and it is logical to close these in the opposite order of which they are opened because one resource might be dependend on another one.
|
||||
|
||||
It's good practice to use defer to close a response body right after you have opened it. In this way you make sure all resources that have been opened have been closed and in this way it can prevent some bugs.
|
||||
What you will see often is something like this:
|
||||
|
||||
```go
|
||||
func main() {
|
||||
resp, err := http.Get("http://www.foomo.org")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
```
|
||||
You open a resource, check if there is an error and after it use defer to close it before the function returns.
|
||||
|
||||
Another thing to keep in mind with defer is that it will execute with the value given to it at the time. To demonstrate:
|
||||
```go
|
||||
func main() {
|
||||
myVar := "hello"
|
||||
defer fmt.Println(myVar)
|
||||
myVar = "goodbye"
|
||||
}
|
||||
```
|
||||
What do you think this prints? You might think it will print 'goodbye' because that is the last value of the variable before the main function returns.
|
||||
Surprisingly the value printed is 'hello', which is likely the result of a compiler optimization.
|
||||
|
||||
1
foomo/docs/backend/go-by-example/embed.mdx
Normal file
1
foomo/docs/backend/go-by-example/embed.mdx
Normal file
@ -0,0 +1 @@
|
||||
https://gobyexample.com/embed-directive
|
||||
0
foomo/docs/backend/go-by-example/files.mdx
Normal file
0
foomo/docs/backend/go-by-example/files.mdx
Normal file
0
foomo/docs/backend/go-by-example/goroutines.mdx
Normal file
0
foomo/docs/backend/go-by-example/goroutines.mdx
Normal file
0
foomo/docs/backend/go-by-example/http.mdx
Normal file
0
foomo/docs/backend/go-by-example/http.mdx
Normal file
1
foomo/docs/backend/go-by-example/interfaces.mdx
Normal file
1
foomo/docs/backend/go-by-example/interfaces.mdx
Normal file
@ -0,0 +1 @@
|
||||
todo
|
||||
@ -1 +1,6 @@
|
||||
# map races
|
||||
---
|
||||
Title: Map Races
|
||||
position: 7
|
||||
---
|
||||
|
||||
# Map Races
|
||||
|
||||
103
foomo/docs/backend/go-by-example/mongodb.mdx
Normal file
103
foomo/docs/backend/go-by-example/mongodb.mdx
Normal file
@ -0,0 +1,103 @@
|
||||
---
|
||||
Title: MongoDB
|
||||
position: 5
|
||||
tags:
|
||||
- Go Basics
|
||||
---
|
||||
|
||||
# MongoDB
|
||||
|
||||
Make sure to use the official golang mongo driver:
|
||||
> go.mongodb.org/mongo-driver/mongo
|
||||
|
||||
This documentation is a simplified version of the tutorial on [MongoDB's website](https://www.mongodb.com/blog/post/mongodb-go-driver-tutorial)
|
||||
|
||||
## Set client connections
|
||||
```go
|
||||
clientOptions := options.Client().ApplyURI(<MongoDB-database-URI>)
|
||||
```
|
||||
|
||||
## Connect with the database
|
||||
```go
|
||||
client, err := mongo.Connect(context.TODO(), clientOptions)
|
||||
```
|
||||
|
||||
## Check connection
|
||||
```go
|
||||
err = client.Ping(context.TODO(), nil)
|
||||
```
|
||||
|
||||
A collection is a grouping of MongoDB documents. Documents within a collection can have different fields. A collection is the equivalent of a table in a relational database system. A collection exists within a single database
|
||||
|
||||
<img src={require('@site/static/img/mongodb.png').default} />
|
||||
source: Geeks for Geeks https://www.geeksforgeeks.org/mongodb-database-collection-and-document/
|
||||
|
||||
JSON documents in MongoDB are stored in a binary representation called BSON (Binary-encoded JSON). Unlike other databases that store JSON data as simple strings and numbers, the BSON encoding extends the JSON representation to include additional types such as int, long, date, floating point, and decimal128. This makes it much easier for applications to reliably process, sort, and compare data. The Go Driver has two families of types for representing BSON data: The D types and the Raw types.
|
||||
The D family of types is used to concisely build BSON objects using native Go types:
|
||||
* D: A BSON document. This type should be used in situations where order matters, such as MongoDB commands.
|
||||
* M: An unordered map. It is the same as D, except it does not preserve order.
|
||||
* A: A BSON array.
|
||||
* E: A single element inside a D.
|
||||
|
||||
You use filters to get the specific data you ask for.
|
||||
|
||||
## CRUD Operations
|
||||
### Insert one item
|
||||
```go
|
||||
insertResult, err := collection.InsertOne(context.TODO(), <item>)
|
||||
```
|
||||
|
||||
### Insert Many
|
||||
this takes a slice of objects
|
||||
```go
|
||||
my-slice := []interface{}{item1, item2}
|
||||
insertManyResult, err := collection.InsertMany(context.TODO(), my-slice)
|
||||
```
|
||||
|
||||
### Update a single document
|
||||
Requires a filter document to match documents in the database and an update document to describe the update operation.
|
||||
```go
|
||||
filter := bson.D{{"name", “item1”}}
|
||||
update := bson.D{
|
||||
{"$inc", bson.D{ // Increases var1 with 1
|
||||
{“var1”, 1},
|
||||
}},
|
||||
}
|
||||
updateResult, err := collection.UpdateOne(context.TODO(), filter, update)
|
||||
```
|
||||
|
||||
### Find a single document
|
||||
Requires a filter document and a pointer to a value into which the result can be decoded, returns a single result which can be decoded into a value.
|
||||
```go
|
||||
var item_result Item // value into which the result can be decoded
|
||||
err = collection.FindOne(context.TODO(), filter).Decode(&result)
|
||||
```
|
||||
|
||||
### Find multiple documents
|
||||
This method returns a Cursor. A Cursor provides a stream of documents through which you can iterate and decode one at a time. Once a Cursor has been exhausted, you should close the Cursor.
|
||||
```go
|
||||
findOptions := options.Find()
|
||||
var results []*Item
|
||||
cur, err := collection.Find(context.TODO(), bson.D{{}}, findOptions)
|
||||
for cur.Next(context.TODO()) {
|
||||
var elem Item
|
||||
err := cur.Decode(&elem)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
results = append(results, &elem)
|
||||
}
|
||||
cur.Close(context.TODO())
|
||||
```
|
||||
|
||||
### Delete documents
|
||||
You can choose to use collection.DeleteOne() or collection.DeleteMany(), both take a filter document to match the documents in the collection.
|
||||
```go
|
||||
deleteResult, err := collection.DeleteMany(context.TODO(), bson.D{{}})
|
||||
```
|
||||
|
||||
## Close connection
|
||||
Best to keep connection open if you have to do multiple things. It does not make sense to open and close a connection if you have to query the database multiple times.
|
||||
```go
|
||||
err = client.Disconnect(context.TODO())
|
||||
```
|
||||
@ -1,6 +1,48 @@
|
||||
---
|
||||
title: Maps
|
||||
sidebar_position: 3
|
||||
tags:
|
||||
- Go Basics
|
||||
---
|
||||
|
||||
import { GoPlayground } from '../../../src/components/GoPlayground';
|
||||
|
||||
# what you should now about nil maps
|
||||
# Maps
|
||||
|
||||
Maps are unordered key value pairs where each key is unique.
|
||||
Unordered in that context means that the order can be different every time you iterate over its contents.
|
||||
You can add, update, get, or delete keys and values.
|
||||
|
||||
Map lookup operations will always return the value for the requested key and a boolean indicated whether the key was found.
|
||||
In case the key was not found, the value will the default value for its data type (eg false for booleans, empty string for strings, nil for pointers etc)
|
||||
|
||||
```go
|
||||
musicMap := make(map[string]string)
|
||||
|
||||
musicMap["Jimi"] = "Hendrix" // Add key and value pair
|
||||
musicMap["Jimi"] = "Hendrix ❤️" // Update value
|
||||
|
||||
v, found := musicMap["Jimi"] // Get a value for an existing key, will return found==true
|
||||
v, found := musicMap["Jimmy"] // Get value for a non existing key: will return found==false
|
||||
|
||||
delete(musicMap, "Jimi") // Deletes Jimi key value pair
|
||||
```
|
||||
|
||||
## What you should now about nil maps
|
||||
|
||||
Consider the following two maps:
|
||||
|
||||
```go
|
||||
var map1 map[string]int
|
||||
map2 := make(map[string]int)
|
||||
```
|
||||
What is the difference between these two? If you will add keys to one of them the program will panic while you can add keys
|
||||
without a problem to the other. Map1 is a *nil map*, because it has not been initialized. Map2 is an empty map but because it is initialized
|
||||
with the make statement you can add elements to this map later on in your program. Nil maps could for example be used for structs that have optional data. In that case
|
||||
we don't want to allocate them every time, only when the data is present.
|
||||
<br />
|
||||
|
||||
While you can not add elements to a nil map, read operations work just fine. Try it out yourself in the following example:
|
||||
|
||||
<GoPlayground
|
||||
id="Alpsx5uHXCS"
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
# panic and recover
|
||||
|
||||
38
foomo/docs/backend/go-by-example/panic-and-recover.mdx
Normal file
38
foomo/docs/backend/go-by-example/panic-and-recover.mdx
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
title: Panic and Recover
|
||||
sidebar_position: 2
|
||||
tags:
|
||||
- Go Basics
|
||||
---
|
||||
|
||||
import { GoPlayground } from '../../../src/components/GoPlayground';
|
||||
|
||||
# Panic and Recover
|
||||
|
||||
## Panic
|
||||
```panic``` is used whenever our application can no longer function. In Go it's mostly left up to the developer to decide when an error is a problem in your application.
|
||||
```panic``` helps you tell your program it encountered a fatal problem which can not be recovered. Panic always prints a stack trace to help locate the problematic line of code.
|
||||
|
||||
## Panic and Defer
|
||||
```go
|
||||
func main() {
|
||||
fmt.Println("Start")
|
||||
defer fmt.Println("Deferred")
|
||||
panic("Panic")
|
||||
fmt.Println("End")
|
||||
}
|
||||
```
|
||||
The above code will print: 'Start', 'Deferred' and then 'Panic'. This is because defer statements will always be executed even in case of a panic.
|
||||
So the order of execution is: Execute called function, then execute defer statements, and in case of a panic program execution will stop.
|
||||
So even if your application will panic defer statements are handled and therefore resources will be closed accordingly.
|
||||
|
||||
## Panic and Recover
|
||||
Try out the following example:
|
||||
<GoPlayground
|
||||
id="BN8Boz9LRVX"
|
||||
proportion={16/10}
|
||||
/>
|
||||
The function that panics will stop because it can no longer function so we don't see 'Is this printed?' printed.
|
||||
The recover function makes it possible to obtain the error in case a panic occurred, and leaves the decision how to proceed to the programmer.
|
||||
In this example, we decided to just log the error and continue to run. The function that panicked will stop execution at the panic, but the code that called it will continue to execute,
|
||||
which is why we see 'End' being printed.
|
||||
@ -1,9 +1,15 @@
|
||||
---
|
||||
title: Ranging and Looping
|
||||
sidebar_position: 4
|
||||
tags:
|
||||
- Go Basics
|
||||
---
|
||||
|
||||
import { GoPlayground } from '../../../src/components/GoPlayground';
|
||||
|
||||
# ranging and looping
|
||||
# Ranging and Looping
|
||||
|
||||
<GoPlayground
|
||||
id="_zMEwPV3pLD"
|
||||
id="pq2UMFR44h3"
|
||||
proportion={16/10}
|
||||
/>
|
||||
|
||||
/>
|
||||
8
foomo/docs/backend/go-by-example/reflection.mdx
Normal file
8
foomo/docs/backend/go-by-example/reflection.mdx
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
Title: Reflection
|
||||
position: 8
|
||||
---
|
||||
|
||||
# Reflection
|
||||
|
||||
In go variables have a static type.
|
||||
@ -1,8 +1,15 @@
|
||||
---
|
||||
Title: Type Casting
|
||||
position: 6
|
||||
tags:
|
||||
- Go Intermediate
|
||||
---
|
||||
|
||||
import { GoPlayground } from '../../../src/components/GoPlayground';
|
||||
|
||||
# type casting
|
||||
# Type Casting
|
||||
|
||||
<GoPlayground
|
||||
id="nzTf6J8tD8k"
|
||||
id="bYkAVVj7Ton"
|
||||
proportion={16/10}
|
||||
/>
|
||||
|
||||
@ -171,10 +171,9 @@ const config = {
|
||||
// algolia: {
|
||||
// contextualSearch: true,
|
||||
// }
|
||||
// prism: {
|
||||
// theme: lightCodeTheme,
|
||||
// darkTheme: darkCodeTheme,
|
||||
// },
|
||||
prism: {
|
||||
additionalLanguages: ['go'],
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
BIN
foomo/static/img/mongodb.png
Normal file
BIN
foomo/static/img/mongodb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 168 KiB |
Loading…
Reference in New Issue
Block a user