// Package main provides the main entry point for the Hyperledger Fabric Asset Transfer REST API // // @title Hyperledger Fabric Asset Transfer API // @version 1.0 // @description RESTful API for managing assets on Hyperledger Fabric blockchain // @termsOfService http://swagger.io/terms/ // // @contact.name API Support // @contact.url http://www.swagger.io/support // @contact.email support@swagger.io // // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // // @host localhost:8888 // @BasePath /api/v1 // // @schemes http https package main import ( "fmt" "log" "net/http" "spiderman/docs" // Import generated docs "spiderman/internal/api" "spiderman/internal/fabric" "spiderman/internal/logger" "spiderman/internal/middleware" "spiderman/pkg/config" "github.com/gorilla/mux" "github.com/sirupsen/logrus" httpSwagger "github.com/swaggo/http-swagger" ) func main() { // Load configuration from environment variables and .env files cfg := config.LoadConfig() // Update Swagger configuration with values from config.env docs.SwaggerInfo.Host = fmt.Sprintf("%s:%s", cfg.Server.Host, cfg.Server.Port) // Initialize logger logger.Init(&cfg.Log) // Log startup information logger.Logger.WithFields(logrus.Fields{ "environment": cfg.Environment.Environment, "host": cfg.Server.Host, "port": cfg.Server.Port, "swagger_host": docs.SwaggerInfo.Host, "log_level": cfg.Log.Level, "log_format": cfg.Log.Format, }).Info("Starting Hyperledger Fabric Asset Transfer REST API") // Initialize Fabric client logger.Logger.Info("Initializing Fabric client...") fabricClient, err := fabric.NewClient(&cfg.Fabric) if err != nil { logger.Logger.WithError(err).Fatal("Failed to initialize Fabric client") } defer fabricClient.Close() // Create API handler apiHandler := api.NewHandler(fabricClient) // Setup router with middleware router := setupRouter(apiHandler, cfg) // Start server startServer(router, cfg) } func setupRouter(apiHandler *api.Handler, cfg *config.Config) *mux.Router { router := mux.NewRouter() // Add middleware in order router.Use(middleware.Recovery) router.Use(middleware.CORS) router.Use(middleware.Logging) // Swagger documentation route (only in development) if cfg.IsDevelopment() { router.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler) logger.Logger.Info("Swagger documentation enabled at /swagger/") } // API routes api := router.PathPrefix("/api/v1").Subrouter() // Health check router.HandleFunc("/health", apiHandler.HealthCheck).Methods("GET").Name("HealthCheck") // Ledger operations api.HandleFunc("/ledger/init", apiHandler.InitLedger).Methods("POST").Name("InitLedger") // Asset operations with OPTIONS support api.HandleFunc("/assets", apiHandler.GetAllAssets).Methods("GET").Name("GetAllAssets") api.HandleFunc("/assets", apiHandler.CreateAsset).Methods("POST").Name("CreateAsset") api.HandleFunc("/assets", func(w http.ResponseWriter, r *http.Request) {}).Methods("OPTIONS").Name("AssetsOptions") api.HandleFunc("/assets/{id}", apiHandler.GetAssetByID).Methods("GET").Name("GetAssetByID") api.HandleFunc("/assets/{id}/transfer", apiHandler.TransferAsset).Methods("PUT").Name("TransferAsset") api.HandleFunc("/assets/{id}", apiHandler.UpdateAsset).Methods("PUT").Name("UpdateAsset") api.HandleFunc("/assets/{id}", func(w http.ResponseWriter, r *http.Request) {}).Methods("OPTIONS").Name("AssetByIdOptions") api.HandleFunc("/assets/{id}/transfer", func(w http.ResponseWriter, r *http.Request) {}).Methods("OPTIONS").Name("TransferAssetOptions") // Blockchain operations api.HandleFunc("/blockchain/height", apiHandler.GetBlockHeight).Methods("GET").Name("GetBlockHeight") api.HandleFunc("/blockchain/info", apiHandler.GetChainInfo).Methods("GET").Name("GetChainInfo") api.HandleFunc("/blockchain/height", func(w http.ResponseWriter, r *http.Request) {}).Methods("OPTIONS").Name("BlockHeightOptions") api.HandleFunc("/blockchain/info", func(w http.ResponseWriter, r *http.Request) {}).Methods("OPTIONS").Name("ChainInfoOptions") // Transaction operations api.HandleFunc("/transactions/{txid}", apiHandler.GetTransactionByID).Methods("GET").Name("GetTransactionByID") api.HandleFunc("/transactions/{txid}", func(w http.ResponseWriter, r *http.Request) {}).Methods("OPTIONS").Name("TransactionByIdOptions") return router } func startServer(router *mux.Router, cfg *config.Config) { host := cfg.Server.Host port := cfg.Server.Port logger.Logger.WithFields(logrus.Fields{ "host": host, "port": port, "environment": cfg.Environment.Environment, "swagger_url": fmt.Sprintf("http://%s:%s/swagger/index.html", host, port), "health_url": fmt.Sprintf("http://%s:%s/health", host, port), "api_base_url": fmt.Sprintf("http://%s:%s/api/v1", host, port), }).Info("Server configuration") fmt.Printf("Starting REST API server on %s:%s\n", host, port) fmt.Printf("Environment: %s\n", cfg.Environment.Environment) fmt.Printf("Health check: http://%s:%s/health\n", host, port) if cfg.IsDevelopment() { fmt.Printf("Swagger documentation: http://%s:%s/swagger/index.html\n", host, port) } logger.Logger.WithFields(logrus.Fields{ "address": ":" + port, }).Info("Starting HTTP server") if err := http.ListenAndServe(":"+port, router); err != nil { log.Fatal("Failed to start server: ", err) } }