Unit 3: API Development and Server Actions
I. Orientation
Modern web applications separate user-interface rendering from operations that read and modify data. APIs provide structured communication between clients and servers, while server actions allow trusted server-side functions to be called directly from application components or forms. In frameworks such as Next.js, these mechanisms commonly use HTTP, URL routing, JavaScript or TypeScript, and server-side data access.
- Governing principle: The client requests an operation; the server validates the request, performs authorized work, and returns a result.
- HTTP convention: Requests contain a method, URL, headers, and sometimes a body; responses contain a status code, headers, and usually a body.
- Separation of concerns: UI code handles interaction and presentation; server code handles secrets, database access, validation, and mutations.
- Security assumption: Client input is untrusted, even when it originates from a controlled form or application interface.
- Data convention: JSON is common for API data, while
FormDatais useful for forms and binary files. - State convention: After a mutation, the interface must either revalidate server data or update its local state.
II. Route Handlers
A. Route Handlers
Route handlers are server-side functions associated with URL paths that receive HTTP requests and produce HTTP responses.
- Purpose: They expose custom endpoints such as
/api/usersor/api/orders. - File convention: In Next.js App Router, a
route.tsorroute.jsfile defines handlers inside anappdirectory. - Method exports: A handler usually exports functions named
GET,POST,PUT,PATCH, orDELETE. - Server execution: Database credentials and private services can remain on the server because route-handler code is not sent to the browser.
- Example:
// app/api/status/route.ts
export async function GET() {
return Response.json({ status: "ok" });
}- HTTP result: The example returns JSON with the default successful status, normally
200 OK.
III. REST APIs
A. REST APIs
A REST API models application data as resources identified by URLs and manipulated through standardized HTTP methods.
- Resource naming:
/api/productsrepresents a collection;/api/products/42represents product42. - Statelessness: Each request contains the information needed to process it; the server does not rely on hidden client interaction history.
- Representation: A product may be represented as JSON such as
{ "id": 42, "name": "Keyboard" }. - Uniform interface: Clients use predictable URL and method combinations rather than separate action-style URLs for every operation.
- Status communication:
201 Createdindicates successful creation, while404 Not Foundindicates that a requested resource does not exist. - Practical limitation: REST endpoints can require several network requests when a screen needs related resources; caching and endpoint design must address this cost.
IV. HTTP Methods
A. HTTP Methods
HTTP methods communicate the intended operation and help servers process requests consistently.
- GET: Reads data and should not intentionally change server state. Example:
GET /api/products/42. - POST: Creates a subordinate resource or starts an operation. Example: submitting a new product to
/api/products. - PUT: Replaces a resource representation, commonly sending all required fields.
- PATCH: Partially updates a resource, such as changing only
price. - DELETE: Removes a resource, for example
DELETE /api/products/42. - Idempotence: Repeating a
PUTorDELETEshould produce the same intended final state; repeatingPOSTmay create multiple records. - Safety:
GETis considered safe because it is intended for retrieval, not mutation.
V. Dynamic Route Handlers
A. Dynamic Route Handlers
Dynamic route handlers use variable URL segments to process requests for individual resources.
- Path convention:
app/api/products/[id]/route.tscaptures a URL such as/api/products/42. - Parameter access: The route parameter identifies which database record to read or modify.
- Example:
type Context = { params: Promise<{ id: string }> };
export async function GET(
_request: Request,
{ params }: Context
) {
const { id } = await params;
return Response.json({ productId: id });
}- Type conversion: URL parameters arrive as strings, so
"42"may need conversion withNumber(id)before numeric database queries. - Validation: An invalid identifier should return
400 Bad Request, while a valid but missing record should return404 Not Found. - Security boundary: A dynamic identifier must still be checked against the authenticated user’s permissions.
VI. Request and Response Handling
A. Request and Response Handling
Request and response handling converts HTTP data into usable values and communicates success or failure clearly.
- Reading query data:
new URL(request.url).searchParams.get("q")reads a query such as/api/products?q=usb. - Reading JSON:
await request.json()parses a JSON body; malformed JSON should be handled as a client error. - Reading form data:
await request.formData()returns text fields and uploaded files. - Inspecting headers:
request.headers.get("Authorization")retrieves a bearer-token header when authentication uses tokens. - Response body:
Response.json({ name: "Ada" })serializes an object as JSON. - Explicit status:
return Response.json(
{ error: "Product not found" },
{ status: 404 }
);- Error discipline: Do not expose database stack traces or secrets; return a stable public error message and log diagnostic details securely on the server.
VII. Server Actions
A. Server Actions
Server actions are asynchronous server functions that can be invoked by client interactions, especially forms, without requiring a separately designed API endpoint.
- Declaration: A file or function can use the
"use server"directive to mark server-only code. - Trusted location: Actions may access databases, environment variables, and private APIs directly.
- Input rule: Arguments still originate from users and must be validated before database operations.
- Return convention: An action can return structured state such as
{ success: false, error: "Invalid email" }. - Example:
"use server";
export async function deletePost(id: string) {
if (!/^\d+$/.test(id)) return { error: "Invalid ID" };
// authorize user, then delete the record
return { success: true };
}- API comparison: Route handlers are useful for mobile clients, third-party consumers, and explicit HTTP contracts; server actions are convenient for tightly integrated application mutations.
- Authorization: Authentication must be checked inside the action because a client can attempt to invoke it directly.
VIII. Form Handling
A. Form Handling
Form handling connects browser controls to a server action or route endpoint while preserving accessible, progressively enhanced behavior.
- Native submission: An HTML
<form>submits named controls; a control without anameis generally absent from submitted form data. - Action binding: A server action can be supplied to a form’s
actionattribute. - Example:
<form action={createUser}>
<input name="email" type="email" required />
<button type="submit">Create user</button>
</form>- Server extraction: The action receives
FormData, from whichformData.get("email")retrieves the submitted value. - Pending state: A submit button should be disabled or indicate progress while the action is running, preventing accidental duplicate submissions.
- Accessibility: Use labels connected with
htmlFor, meaningful button text, and an error region such asaria-live="polite".
IX. Form Validation
A. Form Validation
Form validation verifies that submitted values have the correct shape, type, range, and business meaning before processing.
- Client validation: HTML attributes such as
required,minLength={8}, andtype="email"provide immediate feedback but cannot be trusted alone. - Server validation: The server repeats validation because requests can bypass the browser entirely.
- Schema validation: Libraries such as Zod can define a single explicit schema:
const schema = z.object({
email: z.string().email(),
age: z.coerce.number().int().min(18)
});- Error structure: Return field-specific errors, for example
{ fieldErrors: { email: ["Invalid email"] } }, so the UI can place feedback beside the correct control. - Normalization: Trim whitespace and normalize values before checking them, such as
email.trim().toLowerCase(). - Business rules: Validation may include uniqueness, ownership, or allowed state transitions, such as rejecting an already-registered email.
- Security: Validation limits malformed input; authorization separately determines whether the user may perform the operation.
X. File Upload
A. File Upload
File upload transfers binary content from a form to a server, where type, size, storage, and access must be controlled.
- Form encoding: A file form requires
encType="multipart/form-data":
<form action={uploadAvatar} encType="multipart/form-data">
<input name="avatar" type="file" accept="image/png,image/jpeg" />
<button type="submit">Upload</button>
</form>- Extraction:
formData.get("avatar")may return aFile; verifyvalue instanceof Filebefore using it. - Size validation: Reject a file above an application limit, such as
5 * 1024 * 1024bytes for 5 MB. - Type validation: Check MIME type and preferably inspect file content; a renamed executable must not be trusted merely because its filename ends in
.jpg. - Storage choice: Store large files in object storage and save only a controlled URL or key in the database.
- Filename safety: Generate a server-side filename or object key rather than using raw user filenames.
- Access control: Private uploads require authenticated, authorized download paths or signed URLs.
XI. Data Mutations
A. Data Mutations
Data mutations are operations that create, update, or delete persistent application state.
- Transaction boundary: Related writes should use a database transaction so either all required changes commit or none do.
- Authorization order: Authenticate the caller, authorize the specific record, validate input, then mutate data.
- Example flow:
const user = await requireUser();
const input = schema.parse(rawInput);
await db.post.update({
where: { id: input.id, authorId: user.id },
data: { title: input.title }
});- Cache consistency: After changing data, invalidate or revalidate affected paths so later reads do not display stale information.
- Concurrency: Conditional updates, version columns, or database constraints help prevent overwriting another user’s changes.
- Failure handling: Return a predictable error state and avoid claiming success until the database operation completes.
- Idempotency: For payment or retry-sensitive operations, an idempotency key can prevent duplicate effects from repeated requests.
XII. Optimistic UI Updates
A. Optimistic UI Updates
Optimistic UI updates display the expected result immediately and reconcile it with the server response afterward.
- Interaction model: When a user likes a post, the interface may increase
likesfrom10to11before the request finishes. - Latency benefit: The application feels immediate because rendering does not wait for network and database completion.
- Temporary state: Mark the item as pending so repeated clicks do not send conflicting mutations.
- Rollback: If the server rejects the operation, restore the previous value and show an actionable error.
- Server authority: The final server response wins because permissions, validation, and concurrent changes are decided on the server.
- Example pattern:
setLikes(value => value + 1);
try {
await likePost(postId);
} catch {
setLikes(value => value - 1);
}- Suitable operations: Optimistic updates work well for reversible actions such as toggling a like or completing a task.
- Limitations: They are riskier for payments, destructive deletion, inventory counts, or operations whose server result cannot be predicted reliably.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →