Desenvolvendo um sistema de Planejamento Financeiro com Golang

dio-expert-session-finance

Pré Desenvolvimento

  1. Vamos criar um projeto no Github chamado dio-expert-session-finance

    • Depois voltamos aqui para configurar mais nosso repositório. Por enquanto vamos ter apenas arquivos básicos
      • .gitignore
      • README.md
  2. Depois do nosso projeto criado no Github, vamos criar um projeto Go básico.

    • $ mkdir dio-expert-session-finance
    • $ cd dio-expert-session-finance
    • $ go mod init github.com/marcopollivier/dio-expert-session-finance

    Esses comandos vão criar dentro da pasta dio-expert-session-finance um arquivo go.mod. E esse arquivo vai ser a base do nosso projeto.

    Depois disso, você já pode abrir seu projeto na IDE de sua escolha

    • GoLand
    • VSCode
    • Vim
  3. Agora que temos o nosso projeto funcionando corretamente, vamos criar um Hello, World! para termos certeza que tudo está de acordo com o que esperávamos.

    • Dentro da pasta dio-expert-session-finance/cmd/server/ vamos criar o arquivo main.go
    package main
    
    import "fmt"
    
    func main() {
        fmt.Print("Olá, Mundo!")
    }    

    Com isso já vemos que nosso ambiente está ok e funcional, mas ainda não é isso que queremos exatamente, correto?

  4. Mas precisamos evoluir nosso código para começar a tomar forma de uma API.

    package main
    
    import (
           "fmt"
           "net/http"
    )
    
    func main() {
           http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
                   fmt.Fprintf(w, "Olá. Bem vindo a minha página!")
           })
    
           http.ListenAndServe(":8080", nil)
    }

    $ curl curl http://localhost:8080/

  5. Vamos começar a pensar no nosso modelo. Nós queremos criar um sistema pras nossas finanças pessoais. Para isso vamos pensar num modelo para trabalharmos.

    5.1. Nosso modelo financeiro vai ser bem simples, mas flexível o suficiente para evoluirmos no futuro

    • Titulo
    • Valor
    • Tipo (ENTRADA, SAIDA)
    • Data

    5.2. Vamos pensar que, antes de mais nada, queremos retornar um JSON com esse modelo.

    package main
    
    import (
    	"encoding/json"
    	"net/http"
    	"time"
    )
    
    func main() {
    	http.HandleFunc("/transactions", getTransactions)
    
    	_ = http.ListenAndServe(":8080", nil)
    }
    
    type Transaction struct {
    	Title     string
    	Amount    float32
    	Type      int //0. entrada 1. saida
    	CreatedAt time.Time
    }
    
    type Transactions []Transaction
    
    func getTransactions(w http.ResponseWriter, r *http.Request) {
    	if r.Method != "GET" {
    		w.WriteHeader(http.StatusMethodNotAllowed)
    		return
    	}
    
    	w.Header().Set("Content-type", "application/json")
    
    	layout := "2006-01-02T15:04:05"
    	salaryReceived, _ := time.Parse(layout, "2020-04-05T11:45:26")
    	paidElectricityBill, _ := time.Parse(layout, "2020-04-12T22:00:00")
    	var transactions = Transactions{
    		Transaction{
    			Title:     "Salário",
    			Amount:    1200.0,
    			Type:      0,
    			CreatedAt: salaryReceived,
    		},
    		Transaction{
    			Title:     "Conta de luz",
    			Amount:    100.0,
    			Type:      1,
    			CreatedAt: paidElectricityBill,
    		},
    	}
    
    	_ = json.NewEncoder(w).Encode(transactions)
    }
    type Tction struct {
        Title     string    `json:"title"`
        Amount    float32   `json:"amount"`
        Type      int       `json:"type"` //0. entrada 1. saida
        CreatedAt time.Time `json:"created_at"`
    }
  6. E agora vamos fazer um método de inserção (POST)

    http.HandleFunc("/transactions/create", createATransaction)
    
    ...
    
    func createATransaction(w http.ResponseWriter, r *http.Request) {
    	if r.Method != "POST" {
    		w.WriteHeader(http.StatusMethodNotAllowed)
    		return
    	}
    
    	var res = Transactions{}
    	var body, _ = ioutil.ReadAll(r.Body)
    	_ = json.Unmarshal(body, &res)
    
    	fmt.Println(res)
    	fmt.Println(res[0].Title)
    	fmt.Println(res[1].Title)
    }
    [
       {
           "title": "Salário",
           "amount": 1200,
           "type": 0,
           "created_at": "2020-04-05T11:45:26Z"
       }
    ]
    $ curl -X POST 'http://localhost:8080/transactions/create' \
    -H 'Content-Type: application/json' \
    -d '[
            {
                "title": "Salário",
                "amount": 1200,
                "type": 0,
                "created_at": "2020-04-05T11:45:26Z"
            }
        ]'
  7. Hora de refatorar. Vamos colocar em memória e isolar em arquivos e pacotes

  8. Vamos começar a pensar em monitoramento? Então vamos criar um arquivo de Healthcheck

    package actuator
    
    import (
        "encoding/json"
        "net/http"
    )
    
    func Health(responseWriter http.ResponseWriter, request *http.Request) {
        responseWriter.Header().Set("Content-Type", "application/json")
    
        profile := HealthBody{"alive"}
    
        returnBody, err := json.Marshal(profile)
        if err != nil {
            http.Error(responseWriter, err.Error(), http.StatusInternalServerError)
            return
        }
    
        _, err = responseWriter.Write(returnBody)
        if err != nil {
            http.Error(responseWriter, err.Error(), http.StatusInternalServerError)
            return
        }
    }
    
    type HealthBody struct {
        Status string
    }
  9. Vamos aproveitar já que criamos um util e escrever um teste unitário para ele

    package util
    
    import (
    	"testing"
    )
    
    func TestStringToDate(testing *testing.T) {
    	var convertedTime = StringToTime("2019-02-12T10:00:00")
    
    	if convertedTime.Year() != 2019 {
    		testing.Errorf("Converter StringToDate is failed. Expected Year %v, got %v", 2019, convertedTime.Year())
    	}
    
    	if convertedTime.Month() != 2 {
    		testing.Errorf("Converter StringToDate is failed. Expected Month %v, got %v", 2, convertedTime.Month())
    	}
    
    	if convertedTime.Hour() != 10 {
    		testing.Errorf("Converter StringToDate is failed. Expected Hour %v, got %v", 10, convertedTime.Hour())
    	}
    
    }
  10. Vamos começar a pensar em um pouco de qualidade de código também

    10.1. Para fazer análise de código estática, vamos instalar a dependencia do lint

    • $ go get -u golang.org/x/lint/golint

    10.2. E vamos executar nossos primeiros comandos relacionados

    • $ go test ./...
    • $ golint ./...
  11. Vamos configurar o CircleCI

  12. Vamos colocar métricas na nossa aplicação

    $ go get github.com/prometheus/client_golang/prometheus
    $ go get github.com/prometheus/client_golang/prometheus/promauto
    $ go get github.com/prometheus/client_golang/prometheus/promhttp 
    
  13. Para os passos seguintes, nós vamos fazer uma integração com um BD qualquer. Para isso, vamos subir uma imagem Docker do Postgres pra poder fazer o nosso teste.

    Vamos subir o BD via Docker Compose

    host: localhost user: postgres pass: postgres DB: diodb

    version: "3"
    services:
      postgres:
        image: postgres:9.6
        container_name: "postgres"
        environment:
          - POSTGRES_DB=diodb
          - POSTGRES_USER=postgres
          - TZ=GMT
        volumes:
          - "./data/postgres:/var/lib/postgresql/data"
        ports:
          - 5432:5432
    prepare-tests:
       docker-compose -f .devops/postgres.yml up -d
  14. Já com o banco acessível via Docker, vamos criar a base que utilizaremos no nosso teste

    CREATE TABLE transactions (
        id SERIAL PRIMARY KEY,
        title varchar(100),
        amount decimal,
        type smallint,
        installment smallint,
        created_at timestamp 
    );
    
    insert into transactions (title, amount, type, installment, created_at)
    values ('Freela', '100.0', 0, 1, '2020-04-10 04:05:06'); 
    
    select * from transactions;
  15. Agora com a estrutra de banco criada, vamos fazer as alterações necessárias no código. E a primeira delas é baixar a dependência do driver do Postgres.

    Lista de SQLDrivers disponíveis

    Execute o seguinte comando dentro da pasta do projeto

    $ go get -u github.com/lib/pq
  16. E esse é o código que vai manipular as informações do banco de fato

    package postgres
    
    import (
    	"database/sql"
    	"fmt"
    	"github.com/marcopollivier/dio-expert-session-pre-class/model/transaction"
    
    	_ "github.com/lib/pq"
    )
    
    const (
    	host     = "localhost"
    	port     = 5432
    	user     = "postgres"
    	password = "postgres"
    	dbname   = "diodb"
    )
    
    func connect() *sql.DB {
    	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
    	var db, _ = sql.Open("postgres", psqlInfo)
    	return db
    }
    
    func Create(transaction transaction.Transaction) int {
    	var db = connect()
    	defer db.Close()
    
    	var sqlStatement = `INSERT INTO  transactions (title, amount, type, installment, created_at)
    						VALUES ($1, $2, $3, $4, $5)
    						RETURNING id;`
    
    	var id int
    	_ = db.QueryRow(sqlStatement,
    					transaction.Title,
    					transaction.Amount,
    					transaction.Type,
    					transaction.Installment,
    					transaction.CreatedAt).Scan(&id)
    	fmt.Println("New record ID is:", id)
    
    	return id
    }
      
    func main() {
    	//log.Fatal(http.Init())
    
    	//"Outro freela", 400.0, 0, 1, "2020-04-20 12:00:06"
    	postgres.Create(transaction.Transaction{Title: "Outro freela", Amount: 600.0, Type: 0, Installment: 1, CreatedAt: util.StringToTime("2020-04-20T12:00:06")})
    }
    
    func FetchAll() transaction.Transactions {
    	var db = connect()
    	defer db.Close()
    
    	rows, _ := db.Query("SELECT title, amount, type, installment, created_at FROM transactions")
    	defer rows.Close()
    
    	var transactionSlice []transaction.Transaction
    	for rows.Next() {
    		var transaction transaction.Transaction
    		_ = rows.Scan(&transaction.Title,
    					  &transaction.Amount,
    					  &transaction.Type,
    					  &transaction.Installment,
    					  &transaction.CreatedAt)
    
    		transactionSlice = append(transactionSlice, transaction)
    	}
    
    	return transactionSlice
    }
    
    fmt.Print(postgres.FetchAll())
Similar Resources

Simple JWT Golang

sjwt Simple JSON Web Token - Uses HMAC SHA-256 Example // Set Claims claims := New() claims.Set("username", "billymister") claims.Set("account_id", 86

Dec 8, 2022

Basic and Digest HTTP Authentication for golang http

HTTP Authentication implementation in Go This is an implementation of HTTP Basic and HTTP Digest authentication in Go language. It is designed as a si

Dec 22, 2022

OAuth 1.0 implementation in go (golang).

OAuth 1.0 Library for Go (If you need an OAuth 2.0 library, check out: https://godoc.org/golang.org/x/oauth2) Developing your own apps, with this libr

Nov 22, 2022

Validate Django auth session in Golang

GoDjangoSession Valid for django 3.0.5 Usage: package main import ( "encoding/base64" "fmt" "session/auth" "github.com/Kuzyashin/GoDjangoSession"

Aug 23, 2022

An authorization library that supports access control models like ACL, RBAC, ABAC in Golang

An authorization library that supports access control models like ACL, RBAC, ABAC in Golang

Casbin News: still worry about how to write the correct Casbin policy? Casbin online editor is coming to help! Try it at: https://casbin.org/editor/ C

Jan 4, 2023

a Framework for creating mesh networks using technologies and design patterns of Erlang/OTP in Golang

a Framework for creating mesh networks using technologies and design patterns of Erlang/OTP in Golang

Ergo Framework Implementation of Erlang/OTP in Golang. Up to x5 times faster than original Erlang/OTP. The easiest drop-in replacement for your hot no

Jan 5, 2023

Golang Mongodb Jwt Auth Example Using Echo

Golang Mongodb Jwt Auth Example Using Echo

Golang Mongodb Jwt Auth Example Using Echo Golang Mongodb Rest Api Example Using Echo Prerequisites Golang 1.16.x Docker 19.03+ Docker Compose 1.25+ I

Nov 30, 2022

A Sample Integration of Google and GitHub OAuth2 in Golang (GoFiber) utilising MongoDB

Go Oauth Server This is sample OAuth integration written in GoLang that also uses MongoDB. This is a sample TODO Application where people can Create a

Dec 27, 2022

Golang implementation of JWT and Refresh Token

Fiber and JWT with Refresh Token Repo ini adalah demostrasi JWT support refresh token tanpa menggunakan storage Branch Main: unlimited refresh token R

Dec 18, 2022
Oauth2-golang - Oauth2 Golang Mysql

Oauth2-golang - Oauth2 Golang Mysql

Sep 16, 2022
An authorization library that supports access control models like ACL, RBAC, ABAC in Golang
An authorization library that supports access control models like ACL, RBAC, ABAC in Golang

Casbin News: still worry about how to write the correct Casbin policy? Casbin online editor is coming to help! Try it at: https://casbin.org/editor/ C

Jan 2, 2023
Go-Guardian is a golang library that provides a simple, clean, and idiomatic way to create powerful modern API and web authentication.

❗ Cache package has been moved to libcache repository Go-Guardian Go-Guardian is a golang library that provides a simple, clean, and idiomatic way to

Dec 23, 2022
A standalone, specification-compliant, OAuth2 server written in Golang.
A standalone, specification-compliant,  OAuth2 server written in Golang.

Go OAuth2 Server This service implements OAuth 2.0 specification. Excerpts from the specification are included in this README file to describe differe

Dec 28, 2022
goRBAC provides a lightweight role-based access control (RBAC) implementation in Golang.

goRBAC goRBAC provides a lightweight role-based access control implementation in Golang. For the purposes of this package: * an identity has one or mo

Dec 29, 2022
This is an implementation of JWT in golang!

jwt This is a minimal implementation of JWT designed with simplicity in mind. What is JWT? Jwt is a signed JSON object used for claims based authentic

Oct 25, 2022
This package provides json web token (jwt) middleware for goLang http servers

jwt-auth jwt auth middleware in goLang. If you're interested in using sessions, checkout my sessions library! README Contents: Quickstart Performance

Dec 5, 2022
Golang implementation of JSON Web Tokens (JWT)

jwt-go A go (or 'golang' for search engine friendliness) implementation of JSON Web Tokens NEW VERSION COMING: There have been a lot of improvements s

Jan 6, 2023
Golang OAuth2 server library

OSIN Golang OAuth2 server library OSIN is an OAuth2 server library for the Go language, as specified at http://tools.ietf.org/html/rfc6749 and http://

Dec 23, 2022
Platform-Agnostic Security Tokens implementation in GO (Golang)

Golang implementation of PASETO: Platform-Agnostic Security Tokens This is a 100% compatible pure Go (Golang) implementation of PASETO tokens. PASETO

Jan 2, 2023