Most create endpoints I see in client codebases return one of two lazy things: a 200 with the new id, or a 200 with a success message and nothing else. Then the frontend has to make a second request to show the thing it just created, or it guesses at the shape and gets it wrong.
In my starter kit, creating a user returns this, every time:
public function store(StoreUserRequest $request): JsonResponse
{
$user = User::create($request->validated());
return response()->json(['user' => new UserResource($user)], 201);
}
Two decisions are packed into those three lines, and both are deliberate.
First, 201, not 200. A 200 says "fine, done." A 201 says "a resource now exists that didn't before." That distinction matters the day you write a frontend that branches on status, or a test that asserts creation actually happened. My register endpoint does the same — 201 with the user and a token — because registration is also a creation, not a generic success.
Second, the full resource, not a bare id. The frontend gets the exact same UserResource shape it gets from the list endpoint and the show endpoint: id, name, email, role, timestamps. No second fetch, no special-case shape for the create response, no moment where the table shows a row with missing fields while it waits for a refetch.
Consistency is the real point. Look at the rest of the controller and the pattern holds: show returns ['user' => new UserResource($user)], update returns the same envelope after $user->update($request->validated()). One envelope, one resource, everywhere. The only endpoint that breaks the pattern is destroy, and it does so honestly — 204 with no body, because there is nothing left to return.
There's a temptation to return more on create: the created record plus a message plus a redirect URL. I resist it. The frontend already knows what it just submitted; what it needs back is the server's version of the record — the id, the stored role, the timestamps — in the shape it already knows how to render.
If you take one rule from this: never make your frontend fetch what your backend already has in its hands. Return the resource you just created, in the shape you always return it, with the status code that says it now exists.
That pattern, along with the FormRequest validation and the role middleware that guard this endpoint, ships in my Laravel + React SaaS Starter Kit — https://kamranofficial.gumroad.com/l/mhekoig — a $19 one-time boilerplate with Sanctum auth, role-based access, and a working admin panel, so you start from these decisions instead of re-arguing them.
Top comments (0)