Bruno API Client | Blog & News

Build Faster with Bruno Mock Servers: Develop Your Frontend Before the Backend Is Ready

Written by Samuel Thomas | Nov 13, 2026

You have finished the design of a search page. The cards look good, the filters work, and the layout holds up on a phone. Then you hit a wall: the backend API that supplies the data does not exist yet.

Editor's note

This article was written by Samuel Thomas, a guest contributor from the Bruno community who is not a Bruno employee. The views, examples, and recommendations are the author's own. We are grateful to Samuel for sharing this tutorial with our readers.

This is one of the most common delays in software projects. The frontend is ready to go, but it has nothing to talk to. So the frontend developer waits, or worse, hardcodes a pile of fake data inside the components and has to rip it out later.

There is a better way. With Bruno's Mock Servers, you can create a simulated API on your own computer, point your frontend at it, and keep building. In this article, you will learn what that means, why it helps, and how to set it up step by step.

If you are new to APIs, backend, or frontend development, do not worry. We will start from the basics.

How a typical application works

Imagine you are building a student accommodation platform called Uninest. Students should be able to:

  • Create an account
  • Log in
  • Search for available apartments
  • View apartment details
  • Book accommodation

To make this work, you need two major parts.

  1. The frontend is everything users see and interact with: the login page, the search box, the buttons, the forms, and the apartment listings.
  2. The backend is the part users never see directly. It handles application logic, authentication, data processing, and communication with the database.

These two parts talk to each other through an API.

What is an API?

API stands for Application Programming Interface. A simple way to think about it is this: an API is a messenger that carries requests from the frontend to the backend, and carries answers back.

Say a student opens Uninest and searches for apartments in Warri. Here is what happens behind the scenes:

  • The student types "Warri" into the search box.
  • The frontend sends a request to the backend through the API.
  • The backend searches its database for available apartments in Warri.
  • The backend sends the results back to the frontend.
  • The frontend displays the apartments to the student.

Two terms are worth remembering:

  • API request: a message the frontend sends to the backend, asking for information or asking it to do something.
  • API response: the information the backend sends back.

Responses usually come in a format called JSON, which is a simple, readable way to exchange data between applications. A response for our search might look like this:

Example response
{
  "location": "Warri",
  "apartments": [
    {
      "name": "Royal Hostel",
      "price": 150000,
      "available": true
    },
    {
      "name": "Student Lodge",
      "price": 120000,
      "available": true
    }
  ]
}

What happens when the backend is not ready?

Let's put two developers on the Uninest team. Samuel is building the frontend. David is building the backend.

Samuel has finished the apartment search page. David is still working on the API that fetches apartments from the database. Samuel now has a problem. He cannot properly test his search page because the data it needs is not available yet.

He could wait for David to finish, but that slows the whole project down. He could also paste fake data directly into his code, but then he has to find and remove it later, and he risks building the page around data that looks nothing like what the real API will return.

The cleaner solution is API mocking.

What is API mocking?

API mocking means creating a simulated version of an API that behaves like the real one. In plain terms, you set up a fake backend that returns the same kind of response the real backend is expected to return.

For example, Samuel and David agree that the apartments endpoint will return something like this:

Example response
{
  "success": true,
  "apartments": [
    {
      "id": 1,
      "name": "Royal Hostel",
      "location": "Warri",
      "price": 150000
    },
    {
      "id": 2,
      "name": "Student Lodge",
      "location": "Effurun",
      "price": 120000
    }
  ]
}

Samuel can serve this response from a mock API and build his page against it. His frontend code will not care whether the answer came from a real database or a mock. It just receives JSON and displays it.

One thing to keep in mind: mock data does not come from a real database. It is predefined test data that imitates what the backend should eventually return.

What is Bruno?

Bruno is an open-source API client. Developers use it to create, send, organize, and test API requests. If you have used tools like Postman or Insomnia, the idea will feel familiar.

With Bruno, you can:

  • Send requests to an API
  • Inspect the responses
  • Organize requests into collections
  • Save response examples
  • Create mock servers

This article focuses on that last feature.

What is a Bruno Mock Server?

A Bruno Mock Server is a local HTTP server that runs on your computer and pretends to be your API. It receives requests and sends back the responses you configured.

Back to our example. David is supposed to build this endpoint:

Endpoint
GET /api/apartments

It is not ready, so Samuel uses Bruno to run a mock server that answers at the same path:

Mock endpoint
GET http://localhost:4000/api/apartments

To the frontend, this looks like a normal API request. The only difference is that Bruno is answering instead of the real backend.

Bruno gives you three ways to create a mock server:

  • Collection: build the mock from response examples saved in a Bruno collection.
  • API Spec: generate the mock from an OpenAPI specification.
  • Standalone: create mock responses manually, without linking to a collection or spec.

In this tutorial, we will use the first option, since it is the easiest to follow.

Note

At the time of writing, Mock Servers carry a Beta label inside Bruno (version 4.3.0 in the screenshots below). Menus and wording may change slightly in future versions.

Step by step: Building a mock API for Uninest

Our goal is simple. We want Samuel to display apartment listings in his app before David finishes the backend.

1Install Bruno

Download Bruno from the official website at usebruno.com/downloads. It is available for Windows, macOS, and Linux.

When you open Bruno for the first time, you may see a welcome screen with options such as importing from Postman, creating a collection, or starting with a request. The exact screen can vary depending on your version. Whichever you see, we will create a collection.

2Create a collection

A collection is a folder that keeps related API requests together. For Uninest, a full collection might eventually look like this:

For now, we only need one request. Click the plus icon next to Collections, or choose Create Collection from the welcome screen.

Type the name Uninest API. Bruno shows where the collection will be saved on your computer. You can keep the default location or pick your own. Then click Create.

3Create the request

Inside your new collection, create a new request. Leave the type as HTTP, name the request Get All Apartments, set the method to GET, and enter the path /api/apartments.

Be careful with the URL field. The method already comes from the GET dropdown, so type only the path, /api/apartments, and not the word GET as part of it.

Click Create. The request opens in a new tab.

Notice that you did not need a working backend to do this. You have only described a request that will exist one day.

4Create a response example

This is the step that makes mocking possible. A response example is a saved answer that you write yourself, describing what the API should return. Bruno lets you create one without sending anything to a real server.

Open the menu for your request and choose Create Example. Name it 200-apartments-success. You can add a description if you like, but it is optional.

Bruno then opens the example editor. Make sure the status is set to 200 OK, then paste the following JSON into the response body:

Response body
{
  "success": true,
  "apartments": [
    {
      "id": 1,
      "name": "Royal Hostel",
      "location": "Warri",
      "price": 150000
    },
    {
      "id": 2,
      "name": "Student Lodge",
      "location": "Effurun",
      "price": 120000
    }
  ]
}

Click Save. Your example now appears with the request path, the status, and the response body all in one view.

You have now defined what the API should return when someone asks for apartment listings. You have still not built a backend. You have only written down what its answer will look like.

5Create the mock server

Now we turn that example into a working mock. Look at the Mock Servers section at the bottom of the left sidebar and click the plus icon next to it.

Bruno asks for a name and a source. This is where you see the three options we talked about earlier: Collection, API Spec, and Standalone.

Name the server Uninest Mock API, keep Collection as the source, and pick Uninest API from the dropdown. Leave the box checked that says to sync mock responses with collection examples. This keeps your mock in step with your saved examples. Bruno will also choose an available port automatically.

Click Create.

6Check the dashboard and sync your examples

Bruno opens a dashboard for your mock server. It currently shows as Stopped. Under the Responses tab, you can already see your example listed as a mock response, along with the route it answers.

Two other tabs are worth knowing about. The Routes tab lists the endpoints your mock serves, and the Request Log shows every request that hits your server, which is very useful when you are debugging.

Whenever you change an example in your collection, click Sync with Examples to bring the mock up to date. Bruno will warn you that mock responses matching collection examples will be overwritten with the latest example data, while custom mock responses without a matching example will be kept.

7Start the server

Click Start Server. The status changes to Running, and Bruno shows your base URL:

Base URL
http://localhost:4000

So the full address for our endpoint is:

Endpoint URL
http://localhost:4000/api/apartments

If the word localhost is new to you, it simply means your own computer. The number 4000 is the port, which works like a door that your mock server listens at. Bruno uses port 4000 by default, though it will pick another one if that port is busy.

You can test it right away by opening that address in your browser. You should see the JSON you wrote earlier.

8Connect your frontend to the mock server

Now Samuel can do what he wanted to do all along. In his React app, he points the API address at the mock server:

JavaScript
const API_URL = "http://localhost:4000";

async function getApartments() {
  const response = await fetch(`${API_URL}/api/apartments`);

  if (!response.ok) {
    throw new Error("Could not load apartments");
  }

  const data = await response.json();
  return data.apartments;
}

When this code runs, the following happens:

  • The React app sends a GET request to localhost:4000.
  • Bruno receives it and finds the matching route.
  • Bruno returns the JSON you saved.
  • React receives the data and shows the apartment cards.

A good habit here is to keep the base URL in one place, such as an environment variable. When David finishes the real API, Samuel only has to change that one value. Nothing else in the code needs to move.

If you are using Vite, for example, it could look like this:

JavaScript
const API_URL = import.meta.env.VITE_API_URL;

Then you set VITE_API_URL to the mock address during development, and to the real address later.

Testing more than the happy path

A real API does not always say yes. Sometimes a request succeeds, but other times:

  • The user sends invalid information
  • The apartment does not exist
  • There are no apartments to show
  • The server fails

Your frontend needs to handle all of these gracefully. A search page that works with data but crashes on an empty list is not finished.

Bruno lets you add more than one mock response for the same endpoint. Click New Mock Response on the dashboard to create extra ones. Here is a useful set to start with:

Scenario Status code What the response contains
Apartments found 200 A list of apartments
No apartments found 200 An empty apartments array
Invalid request 400 A validation error message
Apartment not found 404 A not found message
Server error 500 An internal server error message

An empty result could look like this:

Empty result
{
  "success": true,
  "apartments": [],
  "message": "No apartments available"
}

And an error could look like this:

Error response
{
  "success": false,
  "message": "Invalid search location"
}

How does Bruno know which response to send?

If you have several responses for one endpoint, Bruno needs a way to choose which to return. That is the job of response matching rules. You can set rules based on request headers, query parameters, or values in the request body.

For example, a request to /api/apartments?location=Warri could return the list of apartments, while a request with a location that does not exist could return an empty response or an error. Responses with no rules act as the default match.

This lets Samuel check his empty states, error messages, and success views without waiting for David to build any of them.

There is also a Delay setting on the dashboard, measured in milliseconds. Adding a delay makes the mock server answer slowly, which is a handy way to see how your loading spinner behaves. Real networks are never instant, and your interface should look fine while it waits.

Where OpenAPI fits in

OpenAPI is a standard way of describing an API. A specification written in this format lists the available endpoints, the HTTP methods, the required parameters, the shape of requests and responses, and the status codes.

If your backend team writes an OpenAPI spec before building the API, Bruno can use it as a source for a mock server. That is the API Spec option we saw earlier. In that case, you do not have to write every example by hand, because Bruno can generate responses from the spec.

This works especially well when the frontend and backend teams agree on the API contract at the start of a project.

Benefits of using Bruno Mock Servers

Faster frontend work. You can start building and testing features right away, instead of waiting for the backend.

Parallel development. Frontend and backend developers can work at the same time without blocking each other.

Easier testing of edge cases. Success, failure, and empty results are all one configuration away.

Predictable data. A mock returns the same answer every time, so you can repeat a test without worrying about database records changing underneath you.

Earlier feedback. Frontend problems show up sooner, which means fewer surprises during integration.

Local and simple. The mock server runs on your own machine. There is nothing to deploy and no cloud setup needed.

Team friendly. Mock server setups are stored with your workspace files, so they work well with Git and can be shared with teammates.

Limitations to keep in mind

A mock server is not a backend, and it should never be treated like one. Here is the difference:

Mock server Real backend
Returns predefined responses Runs real application logic
Uses configured test data Reads from and writes to a database
Imitates API behavior Implements actual API features
Helpful during development Required for production
Does not store new data by itself Can create, update, and delete data

A few practical lessons follow from this:

  • A mock may not match the final backend exactly. If David changes a field name in the backend code, Samuel's mock will not warn him.
  • Mock servers do not replace testing against the real API.
  • The frontend and backend teams must agree on the response structure, and keep that agreement updated. This is what an OpenAPI Spec is for: it is a shared, written description of the API’s endpoints and responses that both teams (and tools like Bruno) can work from.
  • A mock won’t reject a bad login or an invalid form submission. If your frontend handles those errors, add mocked error responses (like a 401 or 422) so you can build and test that behavior.

When the real backend is ready, switch the base URL from the mock to the real API and run proper integration tests. This is the moment where any gap between the mock and reality will show up, and it is much better to find it early.

Conclusion

Waiting for a backend should not stop a frontend from moving forward. With Bruno Mock Servers, you can describe how an API will respond, run that description as a local server, and build your interface against it today.

In this tutorial, we created a collection, saved a response example, turned it into a mock server, and connected a React app to it. Along the way, we looked at how to test errors and empty states, how OpenAPI can generate mocks for you, and why a mock should never be mistaken for the real thing.

If you are working on a project where the backend is running behind, try it on your next feature. Start with a single endpoint, like the apartments list in our example. Once you see your frontend come alive with realistic data, you will wonder why you ever waited.

Build your first mock server today.

Download Bruno