Claude Code দিয়ে Go API স্ক্যাফোল্ডিং: এক পরিষ্কার handler-service-error প্যাটার্ন নির্ধারণ করুন, তারপর নতুন এন্ডপয়েন্ট জেনারেট করুন যা আপনার Go API জুড়ে ধারাবাহিক থাকে।

Go API সাধারণত শুরুতে পরিষ্কার থাকে: কয়েকটি এন্ডপয়েন্ট, এক বা দুইজন ডেভেলপার, এবং সবকিছু প্রত্যেকের মনে থাকে। তারপর API বাড়ে, ফিচার চাপের মধ্যে শিপ হয়, এবং ছোট ছোট পার্থক্য এসে পড়ে। প্রতিটা পার্থক্য নির্দিষ্টভাবে ক্ষতিকর মনে না হলেও, একসঙ্গে এগুলো ভবিষ্যত সকল পরিবর্তন ধীর করে দেয়।
একটি সাধারণ উদাহরণ: এক হ্যান্ডলার JSON ডিকোড করে একটি স্ট্রাক্টে এবং 400 রিটার্ন করে সহায়ক একটি বার্তা, আরেকটি 422 রিটার্ন করে ভিন্ন আকারে, এবং তৃতীয়টি ত্রুটিগুলো ভিন্ন ফরম্যাটে লগ করে। এগুলো কম্পাইলেশনে ব্যর্থ করে না। এটি শুধু প্রতিটি নতুন কাজ করার সময় ধারাবাহিক সিদ্ধান্ত-গ্রহণ এবং ক্ষুদ্র রিরাইট তৈরি করে।
আপনি এই বিশৃঙ্খলা অনুভব করবেন এমন জায়গাগুলোতে যেমন:
CreateUser, AddUser, RegisterUser) খোঁজাখুঁজি কঠিন করে তোলে।এখানে "Scaffolding" মানে নতুন কাজের জন্য একটি পুনরাবৃত্তি যোগ্য টেমপ্লেট: কোড কোথায় যাবে, প্রতিটি লেয়ার কি করবে, এবং প্রতিক্রিয়াগুলো কেমন হবে। এটা অনেকটাই কোড উৎপন্ন করার চেয়ে একটি স্থির আকার লক করার ব্যাপার।
Claude-এর মতো টুল নতুন এন্ডপয়েন্ট দ্রুত scaffold করতে সাহায্য করতে পারে, কিন্তু এগুলো তখনই কার্যকর থাকে যখন আপনি প্যাটার্নকে একটি নিয়ম হিসেবে বিবেচনা করেন। আপনি নিয়ম নির্ধারণ করবেন, প্রতিটি ডিফ রিভিউ করবেন, এবং টেস্ট চালাবেন। মডেল স্ট্যান্ডার্ড অংশগুলো পূরণ করে; এটি আপনার আর্কিটেকচার পুনরায় নির্ধারণ করার অধিকার পায় না।
Go API তখনই সহজে বড় হয় যখন প্রতিটি অনুরোধ একই পথে চলে। নতুন এন্ডপয়েন্ট জেনারেট করার আগে এক লেয়ার বিভাজন বাছাই করুন এবং সেটির সাথে অনড় থাকুন।
হ্যান্ডলারের কাজ কেবল HTTP: অনুরোধ পড়া, সার্ভিস কল করা, এবং রেসপন্স লেখা। এতে ব্যবসায়িক নিয়ম, SQL, বা "এই একটাই বিশেষ কেস" লজিক থাকা উচিত নয়।
সার্ভিস ইউজকেসের মালিক: ব্যবসায়িক নিয়ম, সিদ্ধান্ত, এবং রেপোজিটরি বা এক্সটার্নাল কলের মধ্যে অর্কেস্ট্রেশন। এটিতে HTTP সংক্রান্ত বিষয় (স্ট্যাটাস কোড, হেডার, অথবা কীভাবে ত্রুটি রেন্ডার করা হবে) থাকা উচিত নয়।
ডাটা অ্যাক্সেস (রিপো/স্টোর) পার্সিস্টেন্সের বিবরণ নিয়ন্ত্রণ করে। এটি সার্ভিসের উদ্দেশ্যকে SQL/কোয়েরি/ট্রানজেকশনে অনুবাদ করে। এখানে ব্যবসায়িক নিয়ম চেপে ধরা উচিত নয়, শুধুমাত্র মৌলিক ডাটা ইন্টেগ্রিটি সীমাবদ্ধতা থাকে।
একটি প্রায়োগিক আলাদা রাখার চেকলিস্ট:
এক নিয়ম বেছে নিন এবং তা দিয়ে আপোষ করবেন না।
একটি সহজ পদ্ধতি:
উদাহরণ: হ্যান্ডলার চেক করে email আছে কি না এবং ই-মেইল মতো দেখাচ্ছে কি। সার্ভিস চেক করে ওই ই-মেইল অনুমোদিত কি না এবং ইতিমধ্যেই ব্যবহার হচ্ছে কি না।
শুরুতেই সিদ্ধান্ত নিন সার্ভিসগুলো ডোমেন টাইপ রিটার্ন করবে নাকি DTO।
একটি পরিষ্কার ডিফল্ট: হ্যান্ডলাররা request/response DTO ব্যবহার করে, সার্ভিস ডোমেন টাইপ ব্যবহার করে, এবং হ্যান্ডলার ডোমেনকে রেসপন্সে ম্যাপ করে। এতে সার্ভিস স্থির থাকে যদিও HTTP কন্ট্রাক্ট পরিবর্তিত হয়।
যদি ম্যাপিং ভারী মনে হয়, তখনও ধারাবাহিকতা রাখুন: সার্ভিস একটি ডোমেন টাইপ এবং একটি টাইপেড এরর রিটার্ন করুক, এবং JSON শেইপিং হ্যান্ডলারে রাখুন।
যদি আপনি চান যে জেনারেট হওয়া এন্ডপয়েন্টগুলো একই ব্যক্তির লেখা মনে হোক, তাহলে ত্রুটি রেসপন্স আগে থেকেই লক করে রাখুন। জেনারেশন তখনই ভালো ফল দেয় যখন আউটপুট ফরম্যাট অ-আলোচ্য: একটি JSON শেইপ, একটি স্ট্যাটাস-কোড ম্যাপ, এবং কি প্রকাশ করা হবে তার এক নিয়ম।
প্রথমে একটি একক ত্রুটি এনভেলপ শুরু করুন যা প্রতিটি এন্ডপয়েন্ট ফেলিওরের সময় রিটার্ন করে। এটিকে ছোট এবং পূর্বানুমেয় রাখুন:
{
"code": "validation_failed",
"message": "One or more fields are invalid.",
"details": {
"fields": {
"email": "must be a valid email address",
"age": "must be greater than 0"
}
},
"request_id": "req_01HR..."
}
code মেশিনের জন্য (স্থিতিশীল ও পূর্বানুমেয়) এবং message মানুষের জন্য (ছোট ও নিরাপদ)। ঐচ্ছিক স্ট্রাকচার্ড ডেটা details-এ রাখুন। ভ্যালিডেশনের জন্য details.fields ম্যাপ সহজে জেনারেটযোগ্য এবং ক্লায়েন্টগুলোর কাছে ইনপুটের পাশে দেখানো সুবিধাজনক।
পরবর্তী ধাপে একটি স্ট্যাটাস কোড ম্যাপ লিখে সেটি মেনে চলুন। প্রতিটি এন্ডপয়েন্টে বিতর্ক যত কম, তত ভালো। যদি আপনি 400 এবং 422 দুটিই চান, বিভাজন স্পষ্টভাবে করে রাখুন:
bad_json -> 400 Bad Request (বিকৃত JSON)validation_failed -> 422 Unprocessable Content (ভাল-ফর্ম্যাট করা JSON, অবৈধ ফিল্ড)not_found -> 404 Not Foundconflict -> 409 Conflict (ডুপ্লিকেট কী, ভার্সন মিল না করা)unauthorized -> 401 Unauthorizedforbidden -> 403 Forbiddeninternal -> 500 Internal Server Errorআপনি কী লগ করবেন বনাম কী রিটার্ন করবেন তা নির্ধারণ করুন। একটি ভাল নিয়ম: ক্লায়েন্টকে একটি নিরাপদ মেসেজ এবং একটি request ID দিন; লগে পুরো এ্যারর এবং অভ্যন্তরীণ কনটেক্সট (SQL, আপস্ট্রীম পে-লোড, ইউজার আইডি) রাখুন যা কখনো লিক করা উচিত নয়।
শেষে, request_id স্ট্যান্ডার্ড করুন। ইনকামিং ID হেডার গ্রহণ করুন যদি থাকে (API গেটওয়ে থেকে), নচেৎ এজ-এ (মিডলওয়্যারে) একটি জেনারেট করুন। এটিকে কনটেক্সটে লাগান, লগে অন্তর্ভুক্ত করুন, এবং প্রতিটি ত্রুটি রেসপন্সে রিটার্ন করুন।
যদি আপনি চান স্ক্যাফোল্ডিং ধারাবাহিক থাকে, আপনার ফোল্ডার লেআউট সাধারণ এবং পুনরাবৃত্তিশীল হতে হবে। জেনারেটররা ধাঁচ অনুসরণ করে, কিন্তু যখন ফাইল ছড়িয়ে থাকে বা নাম প্রতিটি ফিচারে ভিন্ন হয় তখন তারা বিচলিত হয়ে পড়ে।
একটি নামকরণ কনভেনশন বেছে নিন এবং সেটার সঙ্গে আপোষ করবেন না। প্রতিটি জিনিসের জন্য একটি শব্দ নির্বাচন করুন এবং বজায় রাখুন: handler, service, repo, request, response। যদি রুট হয় POST /users, ফাইল ও টাইপের নাম users এবং create চারপাশে রাখুন (কখনো register বা addUser ব্যবহার করবেন না)।
একটি সাধারণ লেআউট যা সাধারণ লেয়ারগুলোর সাথে মেলে:
internal/
httpapi/
handlers/
users_handler.go
services/
users_service.go
data/
users_repo.go
apitypes/
users_types.go
শেয়ারড টাইপগুলি কোথায় থাকবে তা সিদ্ধান্ত নিন, কারণ প্রকল্পগুলো প্রায়ই এখানেই বিশৃঙ্খল হয়ে পড়ে। একটি ব্যবহারযোগ্য নিয়ম:
internal/apitypes-এ থাকবে (JSON এবং ভ্যালিডেশন প্রয়োজন অনুযায়ী)।যদি কোনো টাইপে JSON ট্যাগ থাকে এবং ক্লায়েন্টের জন্য ডিজাইন করা হয়, তাহলে সেটাকে API টাইপ হিসেবে বিবেচনা করুন।
হ্যান্ডলারের ডিপেনডেন্সি ন্যূনতম রাখুন এবং সেই নিয়মটি স্পষ্টভাবে নির্ধারণ করুন:
রেপোর মধ্যে ছোট একটি প্যাটার্ন ডক রিপো রুটে লিখে রাখুন (প্লেইন Markdown ঠিক আছে)। ফোল্ডার ট্রি, নামকরণ নিয়ম, এবং একটি ছোট উদাহরণ ফ্লো (handler -> service -> repo, এবং প্রতিটি অংশ কোন ফাইলে থাকা উচিত) অন্তর্ভুক্ত করুন। এটি ঠিক সেই রেফারেন্স যা আপনি আপনার জেনারেটরে পেস্ট করবেন যাতে প্রতিবার নতুন এন্ডপয়েন্ট একই স্ট্রাকচারে মেলে।
দশটি এন্ডপয়েন্ট জেনারেট করার আগে একটি এন্ডপয়েন্ট তৈরি করুন যেটিতে আপনি আস্থাশীল। এটি গোল্ড স্ট্যান্ডার্ড: সেই ফাইলটি যা আপনি দেখিয়ে বলতে পারবেন, "নতুন কোডকে এভাবেই দেখাতে হবে।" আপনি এটি স্ক্র্যাচ থেকে লিখতে পারেন বা একটি বিদ্যমানকে রিফ্যাক্টর করতে পারেন যতক্ষণ না তা ম্যাচ করে।
হ্যান্ডলার পাতলা রাখুন। একটি চলা টিপ: হ্যান্ডলার ও সার্ভিসের মধ্যে একটি ইন্টারফেস রাখুন যাতে হ্যান্ডলার কনট্রাক্টের ওপর নির্ভর করে, কনক্রিট স্ট্রাকটির ওপর নয়।
রেফারেন্স এন্ডপয়েন্টে ভবিষ্যতে জেনারেটেড কোড কোথায় আটকে থাকতে পারে সেগুলোতে ছোট মন্তব্য রাখুন। সিদ্ধান্তগুলো ব্যাখ্যা করুন (কেন 400 বনাম 422, কেন create 201 রিটার্ন করে, কেন আপনি অভ্যন্তরীণ ত্রুটিগুলো সাধারণ বার্তার আড়াল করেন)। এমন মন্তব্য এড়িয়ে চলুন যা কেবল কোডকে পুনরাবৃত্তি করে।
রেফারেন্স এন্ডপয়েন্ট কাজ করলে হেল্পারগুলো জমা করুন যাতে প্রতিটি নতুন এন্ডপয়েন্টে ড্রিফটের সম্ভাবনা কমে। সবচেয়ে পুনঃব্যবহারযোগ্য হেল্পারগুলো সাধারণত:
নিচে "পাতলা হ্যান্ডলার + ইন্টারফেস" বাস্তবে কেমন দেখাতে পারে:
type UserService interface {
CreateUser(ctx context.Context, in CreateUserInput) (User, error)
}
func (h *Handler) CreateUser(w http.ResponseWriter, r *http.Request) {
var in CreateUserRequest
if err := BindJSON(r, &in); err != nil {
WriteError(w, ErrBadJSON) // 400: malformed JSON
return
}
if err := Validate(in); err != nil {
WriteError(w, err) // 422: validation details
return
}
user, err := h.svc.CreateUser(r.Context(), in.ToInput())
if err != nil {
WriteError(w, err)
return
}
WriteJSON(w, http.StatusCreated, user)
}
কয়েকটি টেস্ট দিয়ে এটিকে লক করুন (এমনকি একটি ছোট টেবিল টেস্টও ঠিক আছে এরর ম্যাপিংয়ের জন্য)। জেনারেশন তখনই ভালো কাজ করে যখন সেটির একটি পরিষ্কার লক্ষ্য থাকে যা অনুকরণ করা যায়।
সামঞ্জস্য শুরু হয় আপনি যা পেস্ট করেন এবং আপনি কী নিষিদ্ধ করেন তার উপর। একটি নতুন এন্ডপয়েন্টের জন্য দুইটি জিনিস দিন:
হ্যান্ডলার, সার্ভিস মেথড, রিকোয়েস্ট/রেসপন্স টাইপ, এবং যেকোন শেয়ারড হেল্পার যা এন্ডপয়েন্টটি ব্যবহার করে তা অন্তর্ভুক্ত করুন। তারপর কনট্রাক্ট স্পষ্টভাবে বলুন:
POST /v1/widgets)নামকরণ, প্যাকেজ পাথ এবং হেল্পার ফাংশন (WriteJSON, BindJSON, WriteError, আপনার ভ্যালিডেটর) ঠিক মিলাতে হবে বলে স্পষ্টভাবে বলুন।
একটি টাইট প্রম্পট "সহায়ক" রিফ্যাক্টরিংকে বন্ধ করে দেয়। উদাহরণ:
Using the reference endpoint below and the pattern notes, generate a new endpoint.
Contract:
- Route: POST /v1/widgets
- Request: {"name": string, "color": string}
- Response: {"id": string, "name": string, "color": string, "createdAt": string}
- Errors: invalid JSON -> 400; validation -> 422; duplicate name -> 409; unexpected -> 500
Output ONLY these files:
1) internal/http/handlers/widgets_create.go
2) internal/service/widgets.go (add method only)
3) internal/types/widgets.go (add types only)
Do not change: router setup, existing error format, existing helpers, or unrelated files.
Must use: package paths and helper functions exactly as in the reference.
আপনি যদি টেস্ট চান, সেগুলো স্পষ্টভাবে অনুরোধ করুন (এবং টেস্ট ফাইলের নাম দিন)। অন্যথায় মডেল সেগুলো স্কিপ করতে পারে বা নতুন টেস্ট সেটআপ উদ্ভাবন করতে পারে।
জেনারেশনের পরে দ্রুত একটি ডিফ চেক করুন। যদি এটি শেয়ারড হেল্পার, রাউটার রেজিস্ট্রেশন, বা আপনার স্ট্যান্ডার্ড এরর রেসপন্স পরিবর্তন করে, আউটপুট প্রত্যাখ্যান করুন এবং "do not change" নিয়মগুলো আরও কড়া করে পুনরায় বলুন।
আউটপুট ঠিকই থাকবে যতটা ইনপুট ধারাবাহিক। প্রতিবার একটি প্রম্পট টেমপলেট পুনরায় ব্যবহার করা এবং আপনার রেপোর একটি ছোট কনটেক্সট স্ন্যাপশট পেস্ট করা দ্রুততর উপায়।
কপি করুন, পেস্ট করুন, এবং প্লেসহোল্ডারগুলো পূরণ করুন:
You are editing an existing Go HTTP API.
CONTEXT
- Folder tree (only the relevant parts):
<paste a small tree: internal/http, internal/service, internal/repo, etc>
- Key types and patterns:
- Handler signature style: <example>
- Service interface style: <example>
- Request/response DTOs live in: <package>
- Standard error response JSON:
{
"error": {
"code": "invalid_argument",
"message": "...",
"details": {"field": "reason"}
}
}
- Status code map:
invalid_json -> 400
invalid_argument -> 422
not_found -> 404
conflict -> 409
internal -> 500
TASK
Add a new endpoint: <METHOD> <PATH>
- Handler name: <Name>
- Service method: <Name>
- Request JSON example:
{"name":"Acme"}
- Success response JSON example:
{"id":"123","name":"Acme"}
CONSTRAINTS
- No new dependencies.
- Keep functions small and single-purpose.
- Match existing naming, folder layout, and error style exactly.
- Do not refactor unrelated files.
ACCEPTANCE CHECKS
- Code builds.
- Existing tests pass (add tests only if the repo already uses them for handlers/services).
- Run gofmt on changed files.
FINAL INSTRUCTION
Before writing code, list any assumptions you must make. If an assumption is risky, ask a short question instead.
এটি কাজ করে কারণ এটি তিনটি জিনিস জোর করে: একটি কনটেক্সট ব্লক (কী আছে), একটি কনস্ট্রেইন্ট ব্লক (কী করা যাবেনা), এবং স্পষ্ট JSON উদাহরণ (তাই শেইপগুলো ভ্রমণ করে না)। ফাইন্যাল ইনস্ট্রাকশন একটি সেফটি ক্যাচ: যদি মডেল অনিশ্চিত হয়, সেটা কোড লেখার আগে আপনাকে জানান।
ধরা যাক আপনি একটি "Create project" এন্ডপয়েন্ট যোগ করতে চান। লক্ষ্য সহজ: একটি নাম গ্রহণ করা, কয়েকটি নিয়ম চালু করা, সেটি স্টোর করা, এবং একটি নতুন আইডি রিটার্ন করা। জটিলতা হল একই handler-service-repo বিভাজন এবং একই ত্রুটি JSON রাখা।
একটি ধারাবাহিক ফ্লো দেখতে এমন:
হ্যান্ডলার যে অনুরোধ গ্রহণ করে তা এইরকম:
{ "name": "Roadmap", "owner_id": "u_123" }
সাফল্যে 201 Created রিটার্ন করুন। ID প্রতি বার এক স্থান থেকে আসা উচিত। উদাহরণস্বরূপ, Postgres সেটি জেনারেট করুক এবং রিপো তা রিটার্ন করুক:
{ "id": "p_456", "name": "Roadmap", "owner_id": "u_123", "created_at": "2026-01-09T12:34:56Z" }
দুটি বাস্তবসম্মত ব্যর্থতার পথ:
যদি ভ্যালিডেশন ব্যর্থ হয় (নাম অনুপস্থিত বা খুব ছোট), আপনার স্ট্যান্ডার্ড শেইপ ব্যবহার করে ফিল্ড-লেভেল এরর রিটার্ন করুন এবং আপনার নির্বাচিত স্ট্যাটাস কোড অনুসরণ করুন:
{ "error": { "code": "VALIDATION_ERROR", "message": "Invalid request", "details": { "name": "must be at least 3 characters" } } }
যদি নাম প্রতি মালিকের জন্য ইউনিক এবং সার্ভিস একটি বিদ্যমান প্রজেক্ট পায়, 409 Conflict রিটার্ন করুন:
{ "error": { "code": "PROJECT_NAME_TAKEN", "message": "Project name already exists", "details": { "name": "Roadmap" } } }
একটি সিদ্ধান্ত যা প্যাটার্ন পরিষ্কার রাখে: হ্যান্ডলার চেক করে "এই অনুরোধটি সঠিকভাবে শেইপ করা আছে কি?" আর সার্ভিস মালিক হয় "এটি অনুমোদিত কি?"। এই বিভাজন জেনারেট হওয়া এন্ডপয়েন্টগুলোকে পূর্বানুমেয় করে।
জেনারেটরকে ইম্প্রোভাইজ করতে দিলে দ্রুত সামঞ্জস্য হারিয়ে যায়।
একটি সাধারণ drift হল নতুন ত্রুটি শেইপ। এক এন্ডপয়েন্ট {error: "..."} রিটার্ন করে, অন্যটি {message: "..."}, আর তৃতীয়টি একটি নেস্টেড অবজেক্ট যোগ করে। এটিকে ঠিক করুন একটি একক ত্রুটি এনভেলপ এবং একটি স্ট্যাটাস কোড ম্যাপ রেখে এক জায়গায়, তারপর নতুন এন্ডপয়েন্টগুলোকে তা পুনঃব্যবহার করতে বাধ্য করুন। যদি জেনারেটর একটি নতুন ফিল্ড প্রস্তাব করে, সেটাকে API পরিবর্তনের অনুরোধ হিসেবে বিবেচনা করুন, কনভেনিয়েন্স হিসেবে নয়।
আরেকটি ড্রিফট হল হ্যান্ডলার ব্লোট। শুরুতে ছোট: validate, তারপর permission checks, তারপর DB query, তারপর ব্যবসায়িক শাখা। একেবারে দ্রুত প্রতিটি হ্যান্ডলার আলাদা দেখায়। একটি নিয়ম রাখুন: হ্যান্ডলার HTTP-কে টাইপ করা ইনপুট ও আউটপুটে ট্রান্সলেট করবে; সার্ভিস সিদ্ধান্তের মালিক; ডাটা অ্যাক্সেস কুয়েরির মালিক।
নামকরণ মিল না থাকাও সমস্যার কারণ। যদি এক এন্ডপয়েন্ট CreateUserRequest ব্যবহার করে এবং অন্যটি NewUserPayload, আপনি টাইপ খুঁজতে এবং গ্লু লেখাতে সময় নষ্ট করবেন। একটি নামকরণ স্কিম বেছে নিন এবং নতুন নাম প্রত্যাখ্যান করুন যদি না একটু জোরালো কারণ থাকে।
কখনো ক্লায়েন্টকে কাঁচা ডাটাবেস এরর রিটার্ন করবেন না। অন্তর্সংগীতি লিক করা ছাড়া, এটি বিভিন্ন এন্ডপয়েন্টে অনিয়মিত মেসেজ এবং স্ট্যাটাস কোড তৈরি করে। অভ্যন্তরীণ ত্রুটিকে ওয়্যাপ করুন, কারণ লগে কারণটি রাখুন, এবং একটি স্থির পাবলিক এরর কোড রিটার্ন করুন।
"কেবল সুবিধার জন্য" নতুন লাইব্রেরি যোগ করা এড়িয়ে চলুন। প্রতিটি অতিরিক্ত ভ্যালিডেটর, রাউটার হেল্পার, বা এরর প্যাকেজ একটি অতিরিক্ত স্টাইল তৈরি করে মেলানো কঠিন করে তোলে।
বহু ভাঙনের প্রতিরোধক:
যদি আপনি দুইটি এন্ডপয়েন্ট ডিফ করতে পারেন না এবং একই আকার দেখতে পান (ইম্পোর্ট, ফ্লো, এরর হ্যান্ডলিং), তাহলে প্রম্পট শক্ত করে পুনরায় জেনারেট করুন মর্জ করার আগে।
কিছু জেনারেট হওয়ার পরে মার্জ করার আগে স্ট্রাকচার প্রথমে চেক করুন। যদি আকার ঠিক থাকে, লজিক বাগ খুঁজে পাওয়া সহজ।
স্ট্রাকচার চেক:
request_id আচরণ।বিহেভিয়ার চেক:
আপনার প্যাটার্নকে একটি শেয়ারড কনট্রাক্ট হিসেবে বিবেচনা করুন, পছন্দ নয়। "কীভাবে আমরা এন্ডপয়েন্ট তৈরি করি" ডকোডটি কোডের পাশে রাখুন এবং একটি রেফারেন্স এন্ডপয়েন্ট রাখুন যা পুরো অ্যাপ্রোচ দেখায়।
জেনারেশন ছোট ব্যাচে স্কেল করুন। বিভিন্ন ধরনের এজ পরীক্ষা করে 2–3 এন্ডপয়েন্ট জেনারেট করুন (একটা সহজ রিড, একটি ভ্যালিডেশন সহ ক্রিয়েট, একটি আপডেট যার নট-ফাউন্ড কেস আছে)। তারপর থামুন এবং সূক্ষ্ম করুন। যদি রিভিউগুলো একই স্টাইল ড্রিফট বারবার খুঁজে পায়, প্রথমে বেসলাইন ডক ও রেফারেন্স এন্ডপয়েন্ট আপডেট করুন তারপর আরো জেনারেট করুন।
আপনি পুনরাবৃত্তি করতে পারেন এমন একটি লুপ:
যদি আপনি একটি শক্ত বাঁধা-বিচার লুপ চান, Koder.ai (koder.ai) মতো একটি vibe-coding প্ল্যাটফর্ম আপনাকে চ্যাট-চালিত ওয়ার্কফ্লোতে দ্রুত স্ক্যাফোল্ড এবং ইটারেট করতে সাহায্য করতে পারে, তারপর যখন এটি আপনার স্ট্যান্ডার্ডের সাথে মিলে যায় তখন সোর্স কোড এক্সপোর্ট করুন। টুলের তুল্য কম গুরুত্বপূর্ণ—নিয়মটাই মূল।
Lock down a repeatable template early: a consistent layer split (handler → service → data access), one error envelope, and a status-code map. Then use a single reference endpoint as the example every new endpoint must copy.
Keep handlers HTTP-only:
If you see SQL, permission checks, or business branching in a handler, push that into the service.
Put business rules and decisions in the service:
The service should return domain results and typed errors—no HTTP status codes, no JSON shaping.
Keep persistence concerns isolated:
Avoid encoding API response formats or enforcing business rules in the repo beyond basic data integrity.
A simple default:
Example: handler checks email is present and looks like an email; service checks it’s allowed and not already in use.
Use one standard error envelope everywhere and keep it stable. A practical shape is:
code for machines (stable)message for humans (short and safe)details for structured extras (like field errors)request_id for tracingThis avoids client-side special cases and keeps generated endpoints predictable.
Write down a status-code map and follow it every time. A common split:
400 for malformed JSON (bad_json)422 for validation failures (validation_failed)404 for missing resources (not_found)409 for conflicts (duplicates/version mismatches)500 for unexpected failuresThe key is consistency: no debating per endpoint.
Return safe, consistent public errors, and log the real cause internally.
code, short message, plus request_idThis prevents leaking internals and avoids random error message differences across endpoints.
Create one “golden” endpoint you trust and require new endpoints to match it:
BindJSON, WriteJSON, WriteError, etc.)Then add a couple of small tests (even table tests for error mapping) to lock the pattern in.
Give the model strict context and constraints:
After generation, reject diffs that “improve” architecture instead of following the baseline.