You have your frontend design all sketched up and ready.
You can't wait to code that thing up!
Everything's going as planned.
And suddenly the backend engineer tells you that the API is not yet ready and will take some time. Bam!
Your ideas flowing through your finger tips to your keyboard then to the editor then to the browser... all stopped.
Well this is exactly where Mirage JS comes to the rescue. It allows you to quickly build mock APIs for your frontend app. And the best part is that it runs in your browser only. You don't need a server for this.
PermalinkSo, lets get started.
We will be building a simple API to get a list of playlists from server and post new playlists.
I will be using React(because I love it) but you can use any other library or framework for your frontend. It will work the same.
I have used codesandbox. You can find the link at the end.
PermalinkCreating the API
Create a file named mock-server.js
and paste the following code:
import { createServer, Model, RestSerializer } from "miragejs";
export const mockServer = () => {
createServer({
serializers: {
application: RestSerializer
},
models: {
playList: Model
},
routes() {
this.timing = 1500;
this.get("/api/play-list", (schema, request) => {
return schema.playLists.all();
});
this.post("/api/play-list", (schema, request) => {
let newPlayList = JSON.parse(request.requestBody).playList;
return schema.playLists.create(newPlayList);
});
},
seeds(server) {
server.create("playList", {
name: "Upbeat"
});
server.create("playList", {
name: "Rock"
});
}
});
};
Well that's a lot. Lets take a few minutes to understand what's happening here.
import { createServer, Model, RestSerializer } from "miragejs";
In the first line, we are importing three things from the mirage package.
createServer
is used to create a new server.Model
is used to define a new model. Think of this like your database.RestSerializer
is used to transform your model to JSON like format.
Next we are exporting mockServer
function which we will call from our App.jsx
file.
Inside this function, we are using the createServer
to create our server instance.
Then we are setting the serializer to RestSerializer
.
After this, we are defining a model named playList
. We will use this to store our playlist names.
Now, lets come to the main part of this: routes
.
Here, we are defining a route which will be our API, which is "/api/play-list"
. There are two methods defined here: get
and post
. We will be getting all the data via get
and posting our new playlist name via post
.
And at the end, we have used seeds(server)
to seed the data (create the models). Here I have created two playlists: Upbeat
and Rock
.
With that, our API is setup and now we need to consume it.
PermalinkConsuming the API
Let's look at the frontend React code now.
We will import our exported mockServer
function here in the App.jsx
:
import { mockServer } from "./api/mock-server";
And we start the mock API server like this:
mockServer();
Next, we have a function to get the data from the server, i.e., from the API.
We are fetching the API via axios
:
const getDataOnClick = async () => {
try {
setIsLoading(true);
const res = await axios.get("/api/play-list");
setPlayList(res.data.playLists);
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
}
And when we get the data from the server, we update the state accordingly.
We also need to post the data via API:
const addNewPlayListOnClick = async () => {
try {
setIsLoading(true);
const res = await axios.post("/api/play-list", {
playList: {
name: inputText
}
});
if (res.status === 201) {
setPlayList((prev) => [...prev, res.data.playList]);
}
setInputText("");
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
};
Here, we are doing a post request to the API and we are sending an object to the API which has a name
as the property.
Note that we are not sending the id
here, it is generated by mirage automatically. We are also updating the state once we get the 201
response status from the server.
Also, I have added some UX hints like loading indicator and we are just console logging the error.
That's it with the logic part. Lets quickly checkout the view:
return (
<div className="App">
<h1>Mirage JS: build mock APIs</h1>
<div>
<input
type="text"
placeholder="Enter new playlist:"
value={inputText}
onChange={(e) => setInputText(e.target.value)}
/>
<button onClick={addNewPlayListOnClick}>Add</button>
</div>
<button onClick={getDataOnClick}>Get all playlists</button>
<h4>Your playlists:</h4>
<ul>
{playList.map((list) => (
<li key={list.id}>
{list.id}. {list.name}
</li>
))}
</ul>
{isLoading && <h3>Loading...</h3>}
</div>
);
This is what our view looks like. We have an input box to get the data from the user and then we have two buttons: Add
and Get all playlists
.
The Add
button calls the addNewPlayListOnClick
function and the Get all playlists
button calls the getDataOnClick
function.
PermalinkAnd that's it.
The user types the name of new playlist and clicks on the Add
button to post the data to the server. If the user clicks on Get all playlists
button, the get request is called and the list is updated in real time.
Checkout the codesandbox for the source code and play around with it.
Also, do checkout the mirage docs .
Thank you for reading. This is my first tutorial blog post on hashnode.
Please share your feedback.
And yes, just reading will not do anything, you need to work on it. So, go on explore mirage and build cool projects!
There is a lot to mirage other than this. As we know:
โA journey, towards a mirage, never ends.โ