A small Go API that generates vacation itineraries through langchaingo using OpenAI-compatible providers (OpenAI and OpenRouter).
The app exposes two endpoints:
POST /Vacation/createto start generating a vacation idea.GET /Vacation/:idto fetch generation status and result.
Generation runs asynchronously in a goroutine, so you create first and then poll by ID.
- Go
- Gin (
github.com/gin-gonic/gin) for HTTP routing - LangChainGo (
github.com/tmc/langchaingo) with OpenAI provider - UUIDs via
github.com/google/uuid
VacationPlanner/
|-- main.go
|-- go.mod
|-- go.sum
|-- .gitignore
|-- chains/
| |-- structs.go
| `-- vacations.go
`-- routes/
|-- structs.go
`-- vacations.go
- Client sends vacation preferences to
POST /Vacation/create. - API returns a generated UUID immediately with
completed: false. - Background goroutine calls an OpenAI-compatible provider using
langchaingo. - Generated itinerary is saved in memory and marked
completed: true. - Client polls
GET /Vacation/:iduntil completed.
- Go installed (project
go.moddeclaresgo 1.25.0) - A valid API key with available quota:
- OpenAI key, or
- OpenRouter key
From project directory:
cd C:\Users\ujjan\Music\Go\VacationPlanner
set "OPENAI_API_KEY=YOUR_OPENAI_KEY"
go run main.goOpenRouter test example:
cd C:\Users\ujjan\Music\Go\VacationPlanner
set "OPENROUTER_API_KEY=YOUR_OPENROUTER_KEY"
set "OPENROUTER_MODEL=openai/gpt-4o-mini"
go run main.goServer starts at:
http://localhost:8080
Request:
POST /Vacation/create
Content-Type: application/jsonBody:
{
"favourite_season": "summer",
"hobbies": ["hiking", "photography"],
"budget": 1500
}curl (cmd.exe):
curl -X POST http://localhost:8080/Vacation/create -H "Content-Type: application/json" -d "{\"favourite_season\":\"summer\",\"hobbies\":[\"hiking\",\"photography\"],\"budget\":1500}"Example response:
{
"id": "c1e0f8d0-48a3-4b2e-a4ee-25dcf58c69d0",
"completed": false
}Request:
GET /Vacation/:idcurl:
curl http://localhost:8080/Vacation/c1e0f8d0-48a3-4b2e-a4ee-25dcf58c69d0Possible responses:
- While processing:
{
"id": "c1e0f8d0-48a3-4b2e-a4ee-25dcf58c69d0",
"completed": false,
"idea": ""
}- After completion:
{
"id": "c1e0f8d0-48a3-4b2e-a4ee-25dcf58c69d0",
"completed": true,
"idea": "..."
}OPENROUTER_API_KEY(optional, preferred for OpenRouter): if set, the app routes requests through OpenRouter.OPENROUTER_MODEL(optional): defaults toopenai/gpt-4o-mini.OPENROUTER_BASE_URL(optional): defaults tohttps://openrouter.ai/api/v1.OPENAI_API_KEY(optional fallback): used whenOPENROUTER_API_KEYis not set.OPENAI_MODEL(optional): defaults togpt-4o-mini.PORT(optional): Gin defaults to8080when not set.
- Never commit API keys.
- Keep keys in environment variables or untracked local files like
.env. - If a key is exposed, rotate/revoke it immediately.
.gitignoreis configured to exclude common secret and local artifact files.
OPENROUTER_API_KEY or OPENAI_API_KEY is not set- Set one of those variables in the same terminal session before
go run.
- Set one of those variables in the same terminal session before
OpenAI generation error: ... 429 ... exceeded your current quota- Billing/quota issue in OpenAI account or project.
- Add credits/payment method, confirm project budget, then use a valid key.
completedstaysfalse- Check server logs right after
POST /Vacation/createfor the real generation error.
- Check server logs right after
- Data is stored in memory (
Vacationsslice) and is lost on restart. - No persistence/database layer.
- No synchronization for concurrent writes to shared in-memory slice.
- No auth/rate limiting for public endpoints.
- Add persistent storage (PostgreSQL or SQLite).
- Add mutex protection around shared in-memory data if kept.
- Add structured error field in API response for failed generation jobs.
- Add tests for routes and chain logic.
- Add Dockerfile and
.env.examplefor easier setup.