1
resposta

Consumindo API do Github em Go | Frontend & Backend

Resouvi refazer esse desafio que ja havia feito antes em Java, so que dessa vez usando Go, isso com intuito de praticar e aprender a mexer melhor com o model "net/http" do Go. Aproveitei e criei um frontend para ficar melhor a realizacao das consultas, ao inves de usar um simples console.

Como ficou o projeto:
Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Codigo Go:
Package domain

package domain

import (
    "encoding/json"
    "fmt"
    "github.com/rickmvi/simple-web-service/internal/api"
    "io"
    "net/http"
    "time"
)

// GithubUser represents a GitHub user profile with relevant information retrieved from the GitHub API.
type GithubUser struct {
    Login       string `json:"login"`
    Name        string `json:"name"`
    AvatarUrl   string `json:"avatar_url"`
    Bio         string `json:"bio"`
    PublicRepos int    `json:"public_repos"`
    Followers   int    `json:"followers"`
    Following   int    `json:"following"`
}

// Handler processes HTTP GET requests to fetch and return GitHub user profile data in JSON format.
func Handler(w http.ResponseWriter, r *http.Request) {

    if r.Method != http.MethodGet {
        http.Error(w, "Method is not supported", http.StatusNotFound)
        return
    }

    username := r.URL.Query().Get("username")
    if username == "" {
        http.Error(w, "Username is required", http.StatusBadRequest)
        return
    }

    url := api.GetUrl(username)

    client := &http.Client{Timeout: 10 * time.Second}

    req, err := http.NewRequest(http.MethodGet, url, nil)

    if err != nil {
        http.Error(w, "error creating request: "+err.Error(), http.StatusInternalServerError)
        return
    }

    req.Header.Set("User-Agent", "go-github-client")

    resp, err := client.Do(req)

    if err != nil {
        http.Error(w, "error when querying GitHub: "+err.Error(), http.StatusInternalServerError)
        return
    }

    defer func(Body io.ReadCloser) {
        if err := Body.Close(); err != nil {
            http.Error(w, "error closing response body: "+err.Error(), http.StatusInternalServerError)
            return
        }
    }(resp.Body)

    body, err := io.ReadAll(resp.Body)
    if resp.StatusCode != http.StatusOK {
        http.Error(w, fmt.Sprintf("GitHub returned: %d - %s", resp.StatusCode, string(body)), resp.StatusCode)
        return
    }

    if err != nil {
        http.Error(w, "error reading response from GitHub: "+err.Error(), http.StatusInternalServerError)
        return
    }

    var user GithubUser
    if err := json.Unmarshal(body, &user); err != nil {
        http.Error(w, "error when unmarshal JSON: "+err.Error(), http.StatusInternalServerError)
        return
    }

    out := GithubUser{
        Login:       user.Login,
        Name:        user.Name,
        AvatarUrl:   user.AvatarUrl,
        Bio:         user.Bio,
        PublicRepos: user.PublicRepos,
        Followers:   user.Followers,
        Following:   user.Following,
    }

    w.Header().Set("Content-Type", "application/json")
    encoder := json.NewEncoder(w)
    if err := encoder.Encode(out); err != nil {
        http.Error(w, "error when encoding JSON: "+err.Error(), http.StatusInternalServerError)
        return
    }
}

Package api

package api

import "fmt"

// GetUrl constructs and returns a GitHub API URL for the specified user.
func GetUrl(user string) (result string) {
    result = fmt.Sprintf("https://api.github.com/users/%s", user)
    return
}

Package main:

package main

import (
    "fmt"
    "github.com/rickmvi/simple-web-service/internal/domain"
    "log"
    "net/http"
)

func main() {
    fileServer := http.FileServer(http.Dir("./static"))
    http.Handle("/", fileServer)
    http.HandleFunc("/api/user", domain.Handler)

    fmt.Printf("Listening on port 3000\n")
    if err := http.ListenAndServe(":3000", nil); err != nil {
        log.Fatalf("ListenAndServe: %v", err)
    }
}

O codigo esta disponivel tanto para fork quanto clone no repositorio simple-web-service. A parte do frontend nao ira cabe aqui no poste, mas ele esta junto no projeto no github.

1 resposta

Oi, Rick! Como vai?

Agradeço por compartilhar.

Gostei muito da sua iniciativa de refazer o desafio em Go, explorando o pacote net/http e ainda criando um frontend para complementar o projeto. Isso mostra um ótimo domínio de integração entre frontend e backend, além de uma boa prática de aprendizado ativo.

Continue praticando dessa forma e ampliando o uso de APIs em outras linguagens.

Alura Conte com o apoio da comunidade Alura na sua jornada. Abraços e bons estudos!