Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CPBR8: Construindo WS com Golang

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/

Edson Hilios

January 24, 2015
Tweet

More Decks by Edson Hilios

Other Decks in Programming

Transcript

  1. Golang Web Services
    Construindo Web Services com Golang
    5 de Fevereiro 2015 – CPBR8
    #dev #golang #webservices

    View full-size slide

  2. Edson Hilios
    Engenheiro @ Centro de Inovação Telefónica | Vivo
    http://edson.hilios.com.br

    View full-size slide

  3. Agenda
    1. Visão geral do Go
    2. Introdução a sintaxe
    3. Configurando seu workspace
    4. Construindo um web service

    View full-size slide

  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.

    View full-size slide

  5. Quem use Go?

    View full-size slide

  6. Por quê Go?
    ● Sintaxe simples*
    ● Alta performance
    ● Excelente biblioteca padrão
    ● Compila rapido
    ● Facil manipulação de threads

    View full-size slide

  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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  10. 0
    1
    2
    3
    Executando
    Execute o comando go run no seu shell.
    $ go run hello.go
    Hello, World!

    View full-size slide

  11. 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)
    }

    View full-size slide

  12. 0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Variaveis
    package main
    import "fmt"
    func main() {
    helloWord := "Hello, World!"
    fmt.Println(helloWord)
    }

    View full-size slide

  13. 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
    )

    View full-size slide

  14. 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)
    }

    View full-size slide

  15. 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
    }

    View full-size slide

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

    View full-size slide

  17. 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"
    // ...

    View full-size slide

  18. 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()

    View full-size slide

  19. 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
    }

    View full-size slide

  20. 0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Estrutura de pastas
    # ~/Golang
    # |-- bin/
    # |-- src/
    # |-- pkg/
    mkdir -p ~/Golang/{bin,src,pkg}

    View full-size slide

  21. 0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Workspace
    /*
    ~/Golang
    |-- src/
    | |-- meuprojeto.com/
    | | |-- funcionalidade/
    | | | |-- *.go
    */
    import "meuprojeto.com/funcionalidade"

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  27. http://localhost:8000

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  33. 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()
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  40. http://localhost:8000/tasks

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  43. 0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    func main() {
    // ...
    task := new(TaskController)
    http.HandleFunc("/task", RestController(task))
    // ...
    }
    Rotas
    main.go

    View full-size slide

  44. http://localhost:8000/task?id=*

    View full-size slide

  45. Code @ GitHub
    http://github.com/hilios/cpbr8app/
    ● POST, PUT, DELETE
    ● Suporte a CORS
    ● App em AngularJS

    View full-size slide

  46. Tks!
    Golang ref: http://gobyexample.com
    Twitter: @hilios
    Site: http://edson.hilios.com.br
    Apresentação: http://speakerdeck.com/hilios
    GitHub: http://github.com/hilios

    View full-size slide