feat: Add backend go examples

This commit is contained in:
melaniegeraldine 2023-03-01 11:32:58 +01:00
parent 776430dfec
commit 30ad429b9b
19 changed files with 294 additions and 14 deletions

View File

@ -0,0 +1 @@
https://gobyexample.com/context

View 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.

View File

@ -0,0 +1 @@
https://gobyexample.com/embed-directive

View File

@ -0,0 +1 @@
todo

View File

@ -1 +1,6 @@
# map races
---
Title: Map Races
position: 7
---
# Map Races

View 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())
```

View File

@ -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"

View File

@ -1,2 +0,0 @@
# panic and recover

View 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.

View File

@ -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}
/>
/>

View File

@ -0,0 +1,8 @@
---
Title: Reflection
position: 8
---
# Reflection
In go variables have a static type.

View File

@ -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}
/>

View File

@ -171,10 +171,9 @@ const config = {
// algolia: {
// contextualSearch: true,
// }
// prism: {
// theme: lightCodeTheme,
// darkTheme: darkCodeTheme,
// },
prism: {
additionalLanguages: ['go'],
},
}),
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB