CPBR8: Construindo WS com Golang

456d07b3f7a1ab66502e232fd9b1d378?s=47 Edson Hilios
January 24, 2015

CPBR8: Construindo WS com Golang

Apresentação feita na CampusParty BR Edição 8 em 5 de Fev, 2015.

Uma introdução e demonstração de como construir web services utilizando Go e o pacote padrão `net/http`. Cria um web service para gerenciar tarefas de um usuário.

http://hilios.github.io/cpbr8app/

456d07b3f7a1ab66502e232fd9b1d378?s=128

Edson Hilios

January 24, 2015
Tweet

Transcript

  1. 1.

    Golang Web Services Construindo Web Services com Golang 5 de

    Fevereiro 2015 – CPBR8 #dev #golang #webservices
  2. 3.

    Agenda 1. Visão geral do Go 2. Introdução a sintaxe

    3. Configurando seu workspace 4. Construindo um web service
  3. 4.

    Go aka Golang É uma linguagem desenvolvida por engenheiros do

    Google em 2007. Com o objetivo de juntar o poder de linguagens como C e Java com a facilidade de escrita e manutenção de código do Python.
  4. 6.

    Por quê Go? • Sintaxe simples* • Alta performance •

    Excelente biblioteca padrão • Compila rapido • Facil manipulação de threads
  5. 7.

    0 1 2 3 4 5 6 7 8 9

    10 Ferramentas $ go build // Compila gerando um executavel $ go run // Compila sem gerar um executavel $ go get // Baixa e instala um pacote $ go install // Compila e instala um pacote $ go test // Executa os testes de um pacote $ go fmt // Formata seu código (Go code-style) $ go vet // Encontra erros que não de compilação $ godoc // Gera a documentação
  6. 8.
  7. 9.

    Caracteristicas • Compilada • Tipada com inferencia • Possui primitivos,

    hash-maps, slices e arrays • Total acesso a memória • Garbage-collected • Não é orientada a objetos • Paradigmas de linguagem funcional
  8. 10.

    0 1 2 3 4 5 6 7 8 9

    10 Hello, World! package main import "fmt" func main() { fmt.Println("Hello, World!") } hello.go
  9. 11.

    0 1 2 3 Executando Execute o comando go run

    no seu shell. $ go run hello.go Hello, World!
  10. 12.

    0 1 2 3 4 5 6 7 8 9

    10 Variaveis package main import "fmt" func main() { var helloWord string helloWord = "Hello, World!" fmt.Println(helloWord) }
  11. 13.

    0 1 2 3 4 5 6 7 8 9

    10 Variaveis package main import "fmt" func main() { helloWord := "Hello, World!" fmt.Println(helloWord) }
  12. 14.

    0 1 2 3 4 5 6 7 8 9

    10 Variaveis const HELLO_WORLD = "Hello, World!" var ( boleano bool inteiro int pontoFlutuante float64 arrayDeStrings []string matriz3por3 [3][3]int mapaDeInteiros map[int]string ponteiro *string )
  13. 15.

    0 1 2 3 4 5 6 7 8 9

    10 Condicionais import "log" if len(x) > 0 { log.Println("Array") } file, err := os.Open("arquivo.txt") if err != nil { log.Fatal(err) }
  14. 16.

    0 1 2 3 4 5 6 7 8 9

    10 Loops sum := 0 for i := 0; i < 10; i++ { sum += i } sum := 0 for i, value := range array { sum += value }
  15. 17.

    0 1 2 3 4 5 6 7 8 9

    10 func HelloTo(name string) string { fmt.Printf("Hello, %s!", name) } // Documentação da função func MultipleReturn (a int) (int, error) { var err error if True { err = fmt.Errorf("Algo errado!") } return a + 1, err } Funções
  16. 18.

    0 1 2 3 4 5 6 7 8 9

    10 Structs type Carro struct { Fabricante, Modelo, Cor string Portas int } focus := Carro{Fabricante: "Ford", Modelo: "Focus", Cor: "Preto", Portas: 5} cruze := new(Carro) cruze.Fabricante = "Chevrolet" // ...
  17. 19.

    0 1 2 3 4 5 6 7 8 9

    10 Métodos func (c *Carro) Buzinar() { fmt.Println("Honk!") } func (c *Carro) String() string { return fmt.Srintf("%s %s cor %d %d portas", c.Fabricante, c.Modelo, c.Cor, c.Portas) } // Executa a função focus.Buzinar()
  18. 20.

    0 1 2 3 4 5 6 7 8 9

    10 Interfaces type RestService interface { Get(data url.Values) http.HandlerFunc Post(data url.Values) http.HandlerFunc Put(data url.Values) http.HandlerFunc Delete(data url.Values) http.HandlerFunc }
  19. 21.
  20. 22.

    0 1 2 3 4 5 6 7 8 9

    10 Estrutura de pastas # ~/Golang # |-- bin/ # |-- src/ # |-- pkg/ mkdir -p ~/Golang/{bin,src,pkg}
  21. 23.

    0 1 2 3 4 5 6 7 8 9

    10 Workspace /* ~/Golang |-- src/ | |-- meuprojeto.com/ | | |-- funcionalidade/ | | | |-- *.go */ import "meuprojeto.com/funcionalidade"
  22. 24.

    0 1 2 3 4 5 6 7 8 9

    10 Workspace # Configura o caminho de importação/instalação export GOPATH=$(cd ~/Golang; pwd) # Adiciona aos executaveis do OS export PATH=$PATH:$GOPATH/bin ~/.bash_profile
  23. 27.

    Projeto Task ID pk Description string Completed bool Verbo Rota

    Descrição GET /tasks Lista todas as Tarefas GET /task?id=* Retorna uma Tarefa POST /task?id=* Cria uma nova Tarefa PUT /task?id=* Atualiza uma Tarefa DELETE /task?id=* Deleta uma Tarefa
  24. 28.

    0 1 2 3 4 5 6 7 8 9

    10 Estrutura # $GOPATH/src/cpbr8app/ # |-- controllers.go # |-- core.go # |-- db.go # |-- main.go # |-- models.go $ mkdir -p $GOPATH/src/cpbr8app $ cd $GOPATH/src/cpbr8app
  25. 29.

    0 1 2 3 4 5 6 7 8 9

    10 package main import "net/http" func helloHandler(rw http.ResponseWriter, r *http.Request) { fmt.Fprint(rw, "Hello, Web!") } func main() { http.HandleFunc("/", helloHandler) http.ListenAndServe(":8000", nil) } main.go Hello, Web! 0 1 2 3 4 5 6 7 8 9 10 11 12
  26. 31.

    0 1 2 3 4 5 6 7 8 9

    10 11 12 13 14 15 import ( "encoding/json" "net/http" "net/url" ) // Interface de um serviço REST type RestInterface interface { Get(values url.Values) (int, interface{}) Post(values url.Values) (int, interface{}) Put(values url.Values) (int, interface{}) Delete(values url.Values) (int, interface{}) } core.go
  27. 32.

    0 1 2 3 4 5 6 7 8 9

    10 11 12 13 14 15 func RestController(i RestInterface) http.HandlerFunc { return func(rw http.ResponseWriter, r *http.Request) { r.ParseForm() // Coleta os dados enviados values := r.Form method := r.Method switch method { case "GET": code, data := i.Get(values) case "POST": code, data := i.Post(values) case "PUT": code, data := i.Put(values) // ... o mesmo para DELETE default: code, data := 405, nil } core.go 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
  28. 33.

    0 1 2 3 4 5 6 7 8 9

    10 11 12 13 14 15 // ... continuação j, err := json.Marshal(data) if err != nil { code = 500 // Internal Server Error } // Lida quando ocorre um erro if code >= 400 { http.Error(rw, http.StatusText(code), code) return } // Escreve o response rw.WriteHeader(code) rw.Write(j) } } core.go 31 32 33 34 35 363 7 38 39 40 41 42 43 44 45 46
  29. 34.

    0 1 2 3 MGO é o driver de MongoDB

    para Golang, o comando go get baixa o repositório para o seu workspace. Instalando dependencias # Instala a biblioteca em ~/Golang/src $ go get labix.org/v2/mgo
  30. 35.

    0 1 2 3 4 5 6 7 8 9

    10 import "labix.org/v2/mgo" var conn *MongoConnection func init() { conn = new(MongoConnection) } db.go Banco de dados
  31. 36.

    0 1 2 3 4 5 6 7 8 9

    10 11 12 13 14 15 db.go type MongoConnection struct { session *mgo.Session } func (m *MongoConnection) Connect() { session, err := mgo.Dial("localhost") if err != nil { panic(err) } m.session = session } func (m *MongoConnection) Close() { m.session.Close() }
  32. 37.

    0 1 2 3 4 5 6 7 8 9

    10 11 12 13 14 15 // Retorna a conexão com o BD global func GetMongoConnection() (*MongoConnection) { return conn } // Retorna uma conexão com o Banco e a sessão utilizada func GetDatabase() (*mgo.Database, *mgo.Session) { session := conn.session.Copy() return session.DB("cpbr8app"), session } db.go
  33. 38.

    0 1 2 3 4 5 6 7 8 9

    10 func main() { db := GetMongoConnection() db.Connect() // Executa somente após esta função terminar defer db.Close() http.HandleFunc("/", helloHandler) http.ListenAndServe(":8000", nil) } Conectando ao BD main.go
  34. 39.

    0 1 2 3 4 5 6 7 8 9

    10 import "labix.org/v2/mgo/bson" type Task struct { Id bson.ObjectId `bson:"_id" json:"id"` Description string `bson:"desc" json:"desc"` Completed bool `bson:"ok" json:"ok"` } type TaskList struct { Tasks []Task `json:tasks` } Modelo models.go
  35. 40.

    0 1 2 3 4 5 6 7 8 9

    10 Modelo func GetTaskList(db *mgo.Database) *TaskList { var tasks []Task collection := db.C("tasks") collection.Find(nil).All(&tasks) return &TaskList{tasks} } models.go
  36. 41.

    0 1 2 3 4 5 6 7 8 9

    10 import "net/url" type TasksController struct{} // Retorna uma lista com todas as Tasks func (t *TasksController) Get(v url.Values) (int, i{}) { db, s := GetDatabase() defer s.Close() return 200, GetTaskList(db) } Controlador 0 1 2 3 4 5 6 7 8 9 10 11 12 controllers.go
  37. 42.

    0 1 2 3 4 5 6 7 8 9

    10 func main() { // ... conexão com o BD tasks := new(TasksController) http.HandleFunc("/tasks", RestController(tasks)) http.HandleFunc("/", helloHandler) http.ListenAndServe(":8000", nil) } Rotas main.go
  38. 44.

    0 1 2 3 4 5 6 7 8 9

    10 Modelo func GetTaskById(db *mgo.Database, id string) *Task { var task Task oid := mgo.ObjectIdHex(id) collection := db.C("tasks") collection.FindId(oid).One(&task) return &task } models.go
  39. 45.

    0 1 2 3 4 5 6 7 8 9

    10 Controlador type TaskController struct{} // Retorna a task pelo ID func (t *TasksController) Get(v url.Values) (int, i{}) { db, s := GetDatabase() defer s.Close() task := GetTaskById(v.Get("id")) if task == nil { return 404, nil } return 200, task } controllers.go
  40. 46.

    0 1 2 3 4 5 6 7 8 9

    10 func main() { // ... task := new(TaskController) http.HandleFunc("/task", RestController(task)) // ... } Rotas main.go