feat: initial project setup
This commit is contained in:
66
README.md
Normal file
66
README.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# Go Book API Example
|
||||||
|
|
||||||
|
This is a simple Go web service that provides a basic API for retrieving book information. It's built using the `chi` router and serves hardcoded book data from memory.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
- `main.go`: Application entry point, sets up the HTTP server and defines the `/books/{id}` endpoint.
|
||||||
|
- `internal/handlers/book_handler.go`: Contains the `BookHandler` responsible for processing requests to the `/books/{id}` endpoint. It uses an in-memory list of books.
|
||||||
|
- `internal/models/book.go`: Defines the `Book` struct used to represent book data.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Go (version 1.16 or higher recommended)
|
||||||
|
|
||||||
|
### Running the Application
|
||||||
|
|
||||||
|
1. **Clone the repository:**
|
||||||
|
```bash
|
||||||
|
git clone <repository_url>
|
||||||
|
cd testing-go-example
|
||||||
|
```
|
||||||
|
(Note: Replace `<repository_url>` with the actual repository URL if this project were hosted.)
|
||||||
|
|
||||||
|
2. **Run the server:**
|
||||||
|
```bash
|
||||||
|
go run main.go
|
||||||
|
```
|
||||||
|
The server will start on `http://localhost:3000`.
|
||||||
|
|
||||||
|
### API Endpoints
|
||||||
|
|
||||||
|
#### `GET /books/{id}`
|
||||||
|
|
||||||
|
Retrieves details for a single book by its ID.
|
||||||
|
|
||||||
|
**Example Request:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3000/books/1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Response:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"title": "The Hitchhiker's Guide to the Galaxy",
|
||||||
|
"author": "Douglas Adams"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3000/books/2
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Response:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "2",
|
||||||
|
"title": "The Restaurant at the End of the Universe",
|
||||||
|
"author": "Douglas Adams"
|
||||||
|
}
|
||||||
|
```
|
||||||
5
go.mod
Normal file
5
go.mod
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module git.workflows.cl/mcabezas/testing-go-example
|
||||||
|
|
||||||
|
go 1.25.4
|
||||||
|
|
||||||
|
require github.com/go-chi/chi/v5 v5.2.3 // indirect
|
||||||
2
go.sum
Normal file
2
go.sum
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
|
||||||
|
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||||
36
internal/handlers/book_handler.go
Normal file
36
internal/handlers/book_handler.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"git.workflows.cl/mcabezas/testing-go-example/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BookHandler struct {
|
||||||
|
books []models.Book
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBookHandler() *BookHandler {
|
||||||
|
return &BookHandler{
|
||||||
|
books: []models.Book{
|
||||||
|
{ID: "1", Title: "El Quijote", Author: "Cervantes"},
|
||||||
|
{ID: "2", Title: "Cien años de soledad", Author: "García Márquez"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *BookHandler) GetBook(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id := chi.URLParam(r, "id")
|
||||||
|
|
||||||
|
for _, book := range h.books {
|
||||||
|
if book.ID == id {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(book)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Error(w, "Book not found", http.StatusNotFound)
|
||||||
|
}
|
||||||
64
internal/handlers/book_handler_test.go
Normal file
64
internal/handlers/book_handler_test.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"git.workflows.cl/mcabezas/testing-go-example/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetBook(t *testing.T) {
|
||||||
|
handler := NewBookHandler()
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/books/1", nil)
|
||||||
|
|
||||||
|
// Configurar contexto de chi con el parámetro id
|
||||||
|
rctx := chi.NewRouteContext()
|
||||||
|
rctx.URLParams.Add("id", "1")
|
||||||
|
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
handler.GetBook(w, req)
|
||||||
|
|
||||||
|
// Verificar código de estado
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Errorf("esperaba status 200, obtuvo %d", w.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar respuesta
|
||||||
|
var book models.Book
|
||||||
|
if err := json.NewDecoder(w.Body).Decode(&book); err != nil {
|
||||||
|
t.Fatalf("error al decodificar: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if book.ID != "1" {
|
||||||
|
t.Errorf("esperaba ID '1', obtuvo '%s'", book.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if book.Title != "El Quijote" {
|
||||||
|
t.Errorf("esperaba título 'El Quijote', obtuvo '%s'", book.Title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetBook_NotFound(t *testing.T) {
|
||||||
|
handler := NewBookHandler()
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/books/999", nil)
|
||||||
|
|
||||||
|
rctx := chi.NewRouteContext()
|
||||||
|
rctx.URLParams.Add("id", "999")
|
||||||
|
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
handler.GetBook(w, req)
|
||||||
|
|
||||||
|
if w.Code != http.StatusNotFound {
|
||||||
|
t.Errorf("esperaba status 404, obtuvo %d", w.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
internal/models/book.go
Normal file
7
internal/models/book.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
type Book struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Author string `json:"author"`
|
||||||
|
}
|
||||||
21
main.go
Normal file
21
main.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
|
"git.workflows.cl/mcabezas/testing-go-example/internal/handlers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r := chi.NewRouter()
|
||||||
|
r.Use(middleware.Logger)
|
||||||
|
|
||||||
|
bookHandler := handlers.NewBookHandler()
|
||||||
|
r.Get("/books/{id}", bookHandler.GetBook)
|
||||||
|
|
||||||
|
log.Println("Servidor en http://localhost:3000")
|
||||||
|
http.ListenAndServe(":3000", r)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user