Product Notes

General best practices when building API, UI and UX

Notes from the internal Coffee notebook

Gaurav GGaurav GSep 29, 2026
Share

With AI doing more and more of the coding, writing software is becoming less of the bottleneck. You can describe a feature, give an agent access to a codebase and have a working version in a surprisingly short amount of time. APIs get created. Screens get built. Forms get wired up. Database queries get written.

This does not make good software automatically easier to build. If anything, it makes the decisions around the code more important.

An AI can create an endpoint that works. It can build a screen that renders. It can connect a form to an API. But whether the endpoint is predictable, whether the screen makes sense, whether the form asks for too much, whether errors are handled properly and whether the whole thing feels coherent still depends on the standards we give it.

Here are some of the best practices for building APIs and screens that are fast, safe and clear to use. Treat them as a starting point and depart from them when a project has a good reason.

API design

Resources and naming

  • Model URLs around nouns, not actions. Use /projects/42/tasks, not /getProjectTasks, and let the HTTP method carry the verb.
  • Use plural nouns and one naming style (snake_case or camelCase) across every endpoint.
    • projects/{project_id} not project/{id}
  • Pick the right method and status code. GET reads, POST creates, PUT or PATCH updates and DELETE removes. Return 201 for created, 204 for no content and 404 for missing.
  • Keep GET requests safe. A GET request should only read data, never create, update or delete it.

Responses

  • Return only the fields the consumer needs. When different screens need different data, offer a fields parameter or separate list and detail shapes.
  • Paginate every list endpoint. Cursor-based pagination holds up better than offsets on data that changes often.
  • Filter, sort and search on the server, including on fields the response doesn't return.
  • Stay consistent in format: one response envelope, ISO 8601 dates in UTC, stable IDs and explicit nulls.

Errors and versioning

  • Return one error shape everywhere: a machine-readable code, a human-readable message and, for validation, the field that failed.

    {
      "error": {
        "code": "VALIDATION_FAILED",
        "message": "The project could not be saved.",
        "field": "customer_gst"
      }
    }
  • Use 4xx error code for client mistakes and 5xx error code for server side errors. Never send a 200 with an error in the body.

  • Version the API from the start, in the path or a header. Don't break existing clients inside a version, and deprecate before you remove.

Reliability and performance

  • Make retries harmless. PUT and DELETE should be idempotent (calling it once or several times has the same effect), and POST endpoints that create records or move money should accept an idempotency key (to avoid duplicate entry creation).
  • Cache slow-changing data with ETag or Cache-Control headers, and rate-limit to protect the service.
  • Watch for N+1 queries behind list endpoints.
  • Index the columns you filter and sort by.

Security

  • Authenticate every request and authorize per resource, not just per endpoint. Check that the caller is allowed to touch that record.
  • Validate all input on the server. Never trust the client.
  • Keep secrets, tokens and personal data out of URLs and logs.
  • Use HTTPS everywhere and limit CORS to the origins you actually need.

Documentation

  • Publish an OpenAPI spec and keep it in step with the code, with example requests and responses.

UI design

Layout and hierarchy

  • Give each screen one primary action and make it the most prominent element.
  • Lead with what matters. Show key data first and put secondary detail behind tabs, expanders or a detail view.
  • Group related information and separate groups with spacing before you reach for borders.
  • Keep screens scannable with clear headings, short line lengths and room to breathe.

Tables and data

  • Show only the columns people use to decide or act. Move long text and rarely used fields to a detail view or a column chooser.
  • Right-align numbers, left-align text and keep units and formats consistent within a column.
  • Avoid horizontal scrolling. If the data is too wide, use sticky key columns, expandable rows or a column chooser.
  • Give long lists sorting, filtering and pagination, and keep row actions in a predictable place.

Forms

  • Ask for the minimum. Every extra field lowers completion.
  • Put labels above fields. Placeholders disappear as soon as someone types, so they can't be the only label.
  • Use the right input for the data, such as date pickers, selects and masks for fixed formats like phone numbers or tax IDs.
  • Group related fields and mark required or optional ones the same way on every form.

Labels and copy

  • Use specific labels and verbs on buttons. "Save changes" beats "Submit".
  • Use one term per concept across the product, and one capitalization style everywhere.
  • Write column titles and headings so a new user understands them without training.

Consistency

  • Build from a shared set of components, spacing, type and colors, so similar things look and behave alike.
  • Use color for meaning, not decoration, and never as the only signal.

Accessibility and responsiveness

  • Use minimum contrast ratio (4.5:1 for normal text) between text and its background, so low-vision users can read it.
  • Set up Keyboard navigation so that every action works via Tab/Enter, not just a mouse click, with a visible outline showing which element is focused.
  • Design for the smallest screen you support first, and keep touch targets around 44 px.

UX

Feedback and states

  • Design every state: loading, empty, error and success. An empty state should say what to do next.
  • Confirm actions with a message after saving, and disable buttons while a request is running so nobody submits twice.
  • Show progress for anything that takes more than about a second, and a real progress bar for long jobs.

Speed

  • Perceived speed matters as much as real speed. Load the important content first, lazy-load the rest and use optimistic updates where failure is unlikely.
  • Fetch data when it's needed, such as when a tab opens, and cache it so going back is instant.

Validation and errors

  • Validate as people go, but don't flag a field before they've finished typing.
  • Put errors next to the field, in plain words that say how to fix the problem.
  • Keep what the user typed when something fails. Never make someone retype a form.
  • Save drafts of long forms.
  • Users should always know where they are, how they got there and how to go back. Use clear page titles, breadcrumbs for deep structures and stable navigation.
  • Remember search and filter state when someone opens a record and returns to the list.
  • Keep the clicks for common tasks low, and put the most frequent tasks closest to hand.

Safety and trust

  • Prefer undo over "Are you sure?" dialogs when an action can be reversed.
  • For irreversible actions, name what will be deleted and put that in the button label.
  • Hide what a user can't use, or explain why it's disabled.

Learn from real use

  • Test with real users early. A handful of sessions turns up the biggest problems.
  • Measure where users drop off and fix the largest problem first.

Checklist before release

  • Endpoints use nouns, consistent names and correct methods and status codes
  • Responses carry only the fields the screen needs, and lists are paginated
  • Errors follow one shape and never hide behind a 200
  • Every request is authenticated and authorized per resource, and input is validated server-side
  • The API is versioned and documented
  • Each screen has one clear primary action
  • Tables fit without horizontal scrolling and hide low-value columns
  • Forms ask for the minimum, with visible labels and inline errors
  • Labels are specific and capitalized the same way everywhere
  • Loading, empty, error and success states are all designed
  • Destructive actions are undoable or clearly labeled
  • Keyboard navigation, contrast and small-screen layouts have been checked
Gaurav G
Gaurav G
admin

Founder at Coffee Inc. Writes about what AI actually amplifies inside an organisation.

More from Gaurav →
Coffeed

In pursuit of sublime.

Our monthly letter on systems thinking and the craft of building.

Coffee Byte

Get notified when we publish.