Introduction: Connecting Your Frontend and Backend

Welcome to the first lesson of this course, where we will set up the API client for your project. In modern web applications, the frontend (what users see and interact with) often needs to communicate with the backend (where data and business logic live). In our case, the frontend is built with React, and the backend uses NestJS.

To make this communication possible, we use an API client. The API client is a set of functions that help your React app send requests to the backend and handle the responses. Setting up this client is the first step in allowing your app to fetch data, show updates, and interact with users in real time.

This lesson makes your React app capable of talking to the backend by creating a small, environment-aware API client and then verifying connectivity from HomePage. We will:

  1. Define environment helpers and base URL candidates (isBrowser, isLocalhost, PORT_HOST, cachedBase, BASE_CANDIDATES) and explain them in depth.
  2. Centralize endpoint paths in a paths helper.
  3. Implement a tiny fetch-based apiClient and a hello() function that calls /api/hello.
  4. Use useEffect in to test the API status and display a user-friendly indicator.
Breaking Down the API Client Code

Let’s look at the main parts of the API client, which lives in src/api/client.ts. Here is the code:

Let’s break this down:

  • Centralized endpoint paths: paths.hello() returns the canonical string "/api/hello". Keeping paths in one object avoids typos and makes future refactors (e.g., prefix changes) a single-edit operation.

  • Hello call flow: hello() performs apiClient.get(paths.hello()), which sends a GET request to /api/hello. It logs successes for dev visibility, throws on errors to let the caller decide how to handle failures, and returns the parsed JSON (the backend “envelope”).

  • Expected envelope: For this endpoint, the backend replies with { success: true, data: "Hello World!" }. Your UI reads success (for status) and may read data (the string) for confirmation.

  • hello is an asynchronous function. It uses to wait for the API response.

Using the API Client on the Home Page

Now, let’s see how the API client is used in the React frontend. Here is the relevant part of src/pages/HomePage.tsx:

Here’s what’s happening:

  • The HomePage component uses React’s useState and useEffect hooks.
  • When the page loads, it calls the hello function from the API client.
  • If the backend responds with { success: true }, it sets the status to "Connected."
  • If there is an error or the response is not successful, it sets the status to "Connection Failed."
  • The status is displayed on the page, so users can see if the frontend is able to talk to the backend.
HomePage useEffect

Let's break down the usage of the useEffect hook we saw in the HomePage.tsx component.

  • State Setters (setServerStatus, setHelloMessage)

    • useState returns a getter and a setter. Calling a setter schedules a re-render with the new value.
    • We initialize serverStatus to "Checking..." so the UI communicates that a health check is in progress.
    • When a response arrives, we flip it to "Connected" or "Connection Failed". If we receive a greeting string in data, we store it in helloMessage.
  • The Effect Lifecycle

    • The effect runs once after the first render because the dependency array is [].
    • Inside the effect, we call hello() which returns a promise resolving to ApiEnvelope<string>.
    • When the promise resolves successfully, we and from the envelope. This mirrors the backend’s global response contract.
Why This Structure Works
  • Environment helpers make URLs portable across local dev, sandboxed ports, and same-origin reverse proxies.
  • A shared paths object removes stringly-typed endpoints and helps avoid typos.
  • Returning the envelope from hello() keeps the calling UI consistent with other endpoints that will be added later.
  • The useEffect pattern with an isMounted guard is robust for small health checks and scales to more complex data fetching where cancellation or staleness matters.

With this foundation, your frontend speaks reliably to the backend and communicates status clearly to users and developers. Next, you can build additional client helpers (auth, books, shelf) using the same envelope pattern and paths registry.

Deep Dive: Breaking Down the API Client Code

Let's review our apiClient code and understand what it does. We'll start with Environment Detection.

Note: This is a deep dive section: it explains why the code is structured the way it is, how environment detection works, and how requests are retried across base URLs.
Understanding this is valuable for debugging and scaling later, but it’s not mandatory — you can skim it now and return later if something breaks.

  • Environment Detection:

    These lines check if the code is running in a browser and if it’s running on your local machine. This helps the client know how to build the correct URL for API requests.

    • isBrowser
    • Checks typeof window !== 'undefined'.
    • Why: In SSR/tests, window doesn’t exist. This flag prevents accidental use of browser-only APIs and lets you adapt URL building to the runtime.
  • isLocalhost

    • Verifies the hostname is exactly localhost or .
Deep Dive: The request<T>() pipeline (step-by-step)

Note: This section is another deep dive into how our generic request function works under the hood.
While it’s useful to understand each stage (headers, candidate URLs, parsing, error handling), you don’t need to memorize all the details to use the API client effectively.

Think of this as "peeking behind the curtain" — a great way to build intuition, but optional if you just want to focus on building features.

  • Headers assembly:
    • Adds Content-Type: application/json only when a body exists; merges user-supplied headers. Keeps GET requests lean and standards-compliant.
  • Candidate loop:
    • Uses cachedBase if known; otherwise iterates BASE_CANDIDATES. Builds url = base + path and performs .
Summary and What’s Next

In this lesson, you learned how to set up an API client to connect your React frontend to your NestJS backend. We covered:

  • Why an API client is important
  • How the client code detects the environment and chooses the right base URL
  • How to make a simple API call to the backend
  • How to use the API client in a React component to show the connection status

You are now ready to practice making and using API calls in your own code. In the next exercises, you will get hands-on experience with these concepts, helping you build confidence in connecting your frontend and backend.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal