Terraform on Naver Cloud - Analyzing of the Go API
To develop my own API in the form of a Terraform Provider, an API is required first. Therefore, this post will cover the development of a Go CRUD API for Terraform Provider development.
[GitHub Repository - Product API in Go] π https://github.com/inpyu/product-api-go
[GitHub Repository - Terraform Provider Cafe Package Client] π https://github.com/inpyu/hashicups-client-go
You can refer to the completed API in the above GitHub repositories.
π https://github.com/hashicorp-demoapp/hashicups-client-go
The API is structured as shown in the diagram. This post will first cover the development of the Product API before moving on to the Client and Provider development.
Project Structure
.
βββ Dockerfile
βββ LICENSE
βββ Makefile
βββ README.md
βββ blueprint
β βββ README.md
β βββ config.json
β βββ stack.hcl
βββ client
β βββ http.go
β βββ http_test.go
βββ conf.json
βββ config
β βββ config.go
β βββ config_test.go
βββ data
β βββ connection.go
β βββ mockcon.go
β βββ model
β βββ cafe.go
β βββ cafe_test.go
β βββ coffee.go
β βββ coffee_test.go
β βββ ingredient.go
β βββ ingredient_test.go
β βββ order.go
β βββ order_test.go
β βββ token.go
β βββ token_test.go
β βββ user.go
β βββ user_test.go
βββ database
β βββ Dockerfile
β βββ products.sql
βββ docker_compose
β βββ conf.json
β βββ docker-compose.yml
βββ functional_tests
β βββ features
β β βββ basic_functionality.feature
β β βββ coffee.feature
β β βββ order.feature
β β βββ user.feature
β βββ helper_test.go
β βββ main_test.go
βββ go.mod
βββ go.sum
βββ handlers
β βββ auth.go
β βββ cafe.go
β βββ coffee.go
β βββ coffee_test.go
β βββ health.go
β βββ ingredients.go
β βββ ingredients_test.go
β βββ order.go
β βββ order_test.go
β βββ user.go
β βββ user_test.go
βββ main
βββ main.go
βββ open_api.yaml
βββ telemetry
β βββ telemetry.go
βββ test_docker
βββ docker-compose.yaml
.
βββ Dockerfile
βββ LICENSE
βββ Makefile
βββ README.md
βββ blueprint
β βββ README.md
β βββ config.json
β βββ stack.hcl
βββ client
β βββ http.go
β βββ http_test.go
βββ conf.json
βββ config
β βββ config.go
β βββ config_test.go
βββ data
β βββ connection.go
β βββ mockcon.go
β βββ model
β βββ cafe.go
β βββ cafe_test.go
β βββ coffee.go
β βββ coffee_test.go
β βββ ingredient.go
β βββ ingredient_test.go
β βββ order.go
β βββ order_test.go
β βββ token.go
β βββ token_test.go
β βββ user.go
β βββ user_test.go
βββ database
β βββ Dockerfile
β βββ products.sql
βββ docker_compose
β βββ conf.json
β βββ docker-compose.yml
βββ functional_tests
β βββ features
β β βββ basic_functionality.feature
β β βββ coffee.feature
β β βββ order.feature
β β βββ user.feature
β βββ helper_test.go
β βββ main_test.go
βββ go.mod
βββ go.sum
βββ handlers
β βββ auth.go
β βββ cafe.go
β βββ coffee.go
β βββ coffee_test.go
β βββ health.go
β βββ ingredients.go
β βββ ingredients_test.go
β βββ order.go
β βββ order_test.go
β βββ user.go
β βββ user_test.go
βββ main
βββ main.go
βββ open_api.yaml
βββ telemetry
β βββ telemetry.go
βββ test_docker
βββ docker-compose.yaml
Understanding the Directory Structure
- client directory
client/
: Contains HTTP client-related code.http.go
: Implements the HTTP client.
- data directory
data/
: Contains database connection and data model files.connection.go
: Handles database connections.mockcon.go
: Implements a mock database connection.model/
: Contains data models for different entities.cafe.go
,coffee.go
,ingredient.go
,order.go
,token.go
,user.go
: Define models for cafes, coffee, ingredients, orders, tokens, and users.
- handlers directory
handlers/
: Contains handlers that process HTTP requests.auth.go
: Handles authentication-related requests.cafe.go
,coffee.go
,ingredients.go
,order.go
,user.go
: Handle requests related to cafes, coffee, ingredients, orders, and users.
Key Components
main.go:
- Functions like a controller in a Spring application.
- Defines routes and request handlers.
client/http.go
:- Handles interaction with external APIs.
- Processes incoming HTTP requests.
data/model
:- Defines entity structures.
data/connection.go
:- Implements database connection and business logic.
handlers
:- Processes HTTP requests on the server side.
- Interacts with the database to return or manipulate data.
While Client and Handler might seem similar, they serve different purposes:
- Client: Gathers data and interacts with external APIs.
- Handler: Processes requests and interacts with the database on the server side.
main.go
Now, letβs examine main.go, its functionalities, and the code implemented in this file.
Router and Middleware Setup
The application uses the gorilla/mux package to configure the router and the cors package to handle CORS settings.
r := mux.NewRouter()
r.Use(hckit.TracingMiddleware)
r.Use(cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"POST", "GET", "OPTIONS", "PUT", "DELETE"},
AllowedHeaders: []string{"Accept", "content-type", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization"},
}).Handler)
Registering Handlers
Various handlers are registered for different endpoints. Each handler is initialized with a database connection and a logger.
healthHandler := handlers.NewHealth(t, logger, db)
r.Handle("/health", healthHandler).Methods("GET")
coffeeHandler := handlers.NewCoffee(db, logger)
r.Handle("/coffees", coffeeHandler).Methods("GET")
ingredientsHandler := handlers.NewIngredients(db, logger)
r.Handle("/coffees/{id:[0-9]+}/ingredients", ingredientsHandler).Methods("GET")
userHandler := handlers.NewUser(db, logger)
r.HandleFunc("/signup", userHandler.SignUp).Methods("POST")
orderHandler := handlers.NewOrder(db, logger)
r.Handle("/orders", authMiddleware.IsAuthorized(orderHandler.GetUserOrders)).Methods("GET")
cafeHandler := handlers.NewCafe(db, logger)
r.Handle("/cafes", cafeHandler).Methods("GET")
r.Handle("/cafes/{id:[0-9]+}", cafeHandler).Methods("GET")
Explanation of Handlers
- Health Check Handler
- /health: Checks the applicationβs health status.
- Coffee Handler
- /coffees: Retrieves a list of coffee products.
- Only authenticated users can create a coffee product.
- Ingredient Handler
- Retrieves the list of ingredients for a specific coffee product.
- User Handler
- Handles user signup and login.
- Order Handler
- Authenticated users can view, create, update, and delete orders.
data/coffee.go
Now, letβs analyze the model package, which defines coffee-related data and handles JSON serialization and deserialization.
Coffees
Type
The Coffees type is a slice of Coffee objects.
FromJSON Method
func (c *Coffees) FromJSON(data io.Reader) error {
de := json.NewDecoder(data)
return de.Decode(c)
}
- Deserializes JSON data into a Coffees type.
- Reads JSON data from an io.Reader and decodes it into a Coffees object.
ToJSON Method
func (c *Coffees) ToJSON() ([]byte, error) {
return json.Marshal(c)
}
Serializes a Coffees object into JSON format.
Coffee
Struct
type Coffee struct {
ID int `db:"id" json:"id"`
Name string `db:"name" json:"name"`
Teaser string `db:"teaser" json:"teaser"`
Collection string `db:"collection" json:"collection"`
Origin string `db:"origin" json:"origin"`
Color string `db:"color" json:"color"`
Description string `db:"description" json:"description"`
Price float64 `db:"price" json:"price"`
Image string `db:"image" json:"image"`
CreatedAt string `db:"created_at" json:"-"`
UpdatedAt string `db:"updated_at" json:"-"`
DeletedAt sql.NullString `db:"deleted_at" json:"-"`
Ingredients []CoffeeIngredient `json:"ingredients"`
}
- Represents a coffee product stored in the database.
- Uses json and db tags for serialization and database mapping.
This analysis covered the API structure and key components. The next steps involve implementing the client and Terraform Provider.
Leave a comment