ข้ามไปยังเนื้อหา

โครงสร้างโปรเจกต์

โปรเจกต์ TypeScript/Node มี package.json, build tool, โฟลเดอร์ dist/ และ node_modules ส่วนโปรเจกต์ Go เรียบง่ายกว่า: go.mod ประกาศ module และ dependency ไม่มีโฟลเดอร์ output แยกต่างหาก — go build สร้าง binary ไฟล์เดียว

TypeScript
// Express / NestJS project tree
my-api/
package.json
tsconfig.json
src/
main.ts
app.module.ts // NestJS root module
books/
books.controller.ts
books.service.ts
books.dto.ts
middleware/
logger.middleware.ts
node_modules/
Go
// Echo project tree
books-api/
go.mod
go.sum
main.go // entry point; wire everything here
internal/
handler/
books.go // HTTP handlers (parse, validate, call service)
service/
books.go // business logic
store/
books.go // database queries
model/
book.go // shared structs / domain types

go.mod ประกาศ module path (ใช้เป็น prefix ของ import) และ Go version ขั้นต่ำ go get เพิ่ม dependency และ go mod tidy ลบอันที่ไม่ได้ใช้

TypeScript
// package.json
{
"name": "books-api",
"version": "1.0.0",
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"typescript": "^5.0.0"
}
}
Go
// go.mod
module github.com/you/books-api
go 1.27
require (
github.com/labstack/echo/v5 v5.3.1
)

ใน NestJS main.ts เรียก NestFactory.create ส่วนใน Echo main.go เรียก echo.New() ลงทะเบียน middleware กับ route แล้วเรียก e.Start ทุกอย่างเป็น Go code ที่ชัดเจน — ไม่มี decorator ไม่มี DI container

TypeScript
// NestJS main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('api');
await app.listen(3000);
}
bootstrap();
Go
// main.go
package main
import (
"log/slog"
"os"
"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware"
"github.com/you/books-api/internal/handler"
"github.com/you/books-api/internal/store"
)
func main() {
e := echo.New()
// Middleware
e.Use(middleware.RequestLogger())
e.Use(middleware.Recover())
// Dependency wiring (manual, no container)
bookStore := store.NewBookStore()
bookHandler := handler.NewBookHandler(bookStore)
// Routes
api := e.Group("/api")
api.GET("/books", bookHandler.List)
api.POST("/books", bookHandler.Create)
api.GET("/books/:id", bookHandler.Get)
api.PUT("/books/:id", bookHandler.Update)
api.DELETE("/books/:id", bookHandler.Delete)
if err := e.Start(":1323"); err != nil {
slog.Error("server stopped", "err", err)
os.Exit(1)
}
}

e.Start จะ block จนกว่า server จะหยุด แล้วคืนสาเหตุมาเป็น error — *slog.Logger ไม่มี Fatal คุณจึงต้อง log และ exit เอง ถ้าต้องการ graceful shutdown หรือ TLS ให้ใช้ echo.StartConfig แทน:

sc := echo.StartConfig{Address: ":1323", GracefulTimeout: 10 * time.Second}
if err := sc.Start(ctx, e); err != nil { // returns when ctx is cancelled
slog.Error("server stopped", "err", err)
}

รันบนเครื่องของคุณ — ต้องการ Echo module และ network port จาก project root ของคุณ: go run main.go

ไฟล์ใดใน Go ที่เทียบเท่า package.json สำหรับประกาศ dependency?
โฟลเดอร์ internal/ บังคับใช้อะไรใน Go?
คำสั่งใดที่ลบ dependency ที่ไม่ได้ใช้ออกจาก go.mod?
ใน Echo การลงทะเบียน route เกิดขึ้นที่ไหน?