Creating Users with POST
Creating Users with POST in a Remix API Route
Welcome! In this lesson, we’re going to add the “create” part of a simple Users API. You already have a Remix route serving data—now you’ll learn how that same route can accept data from the client and add a new user to the in-memory store.
You’ll work in app/routes/api.users.tsx to handle POST /api/users, validate the incoming JSON payload, generate a new user ID, and return the newly-created user with the right HTTP status code. Then you’ll see how the UI in app/routes/_index.tsx triggers that POST request so you can test everything right in the app.
Previously…
In the previous lesson, you served a list of users from an API route and learned how query parameters can shape a response. That’s the “read” side of an API. Now we’ll build the “create” side—accepting JSON input from the frontend and pushing a new record into the same in-memory users collection.
Where POST logic lives in Remix
In Remix API routes, loader() is for read-only requests (typically GET), and action() is for requests that change data (like POST, PUT, PATCH, and DELETE). In this project, both live in the same file: app/routes/api.users.tsx.
That means /api/users supports:
- GET via
loader()(returning theusersarray) - POST via
action()(creating and returning a new user)
| Method | URL | Route file | Handler | Purpose |
|---|---|---|---|---|
| GET | /api/users | api.users.tsx | loader | List users |
| POST | /api/users | api.users.tsx | action | Create a user |
| GET | /api/users/:id | api.users.$id.tsx | loader | Fetch one user |
| PUT/PATCH/DELETE | /api/users/:id | api.users.$id.tsx | action | Replace, partially update, or delete one user |
Returning all users with the loader
This first block is the GET handler in app/routes/api.users.tsx. It returns the current in-memory users array as JSON.
- The
loader()here returnsjson(users), which means the response body is the raw array (not wrapped in{ users: ... }). That’s important because the UI expects the endpoint to behave like a straightforward JSON API. - Even though Remix can pass
{ request }into a loader, this implementation doesn’t need the request object, because it always returns the full array exactly as it exists in memory. - The
console.log(...)is a lightweight way to make requests visible while you’re developing and testing. When you click buttons in the UI, you can confirm which endpoint/method was hit.
