In the last post we successfully implemented authentication and wired together our web app with the API. However, we are still using the temporary local mock API that imitates the task management operations. Now that the real API connected with our database is live on the server, it’s time to replace our mock API with the real one.
Just a quick detour to answer the question: “What was the point in spending time implementing a mock API when it was known in advance that it will be replaced?”.
Building up our backend wasn’t an easy and quick task which you may have noticed if you followed our series.
If we would have implemented backend first, we still couldn’t showcase the app to our users, gather feedback, and iterate on the product. Even though our database, backend, and frontend work well together locally, we still need to set up our infrastructure to be able to go live.
In comparison, doing duplicate work by implementing the mock API, we bought ourselves several weeks head start to gather valuable feedback, and build our presence.
We will replace our mock API with the GraphQL API, so all task operations (creation, reading, updating, deleting) will be done by the live server, and performed on the database. This includes:
mockTaskApi
operations with the hooks provided by the GraphQL API.mockTaskApi
, and MockTaskType
.To begin, we removed the entire mockTaskApi
store from the codebase. This included:
MockTaskType
type.usePopulateTasks
.With the mock layer gone, we transitioned all task-related logic to use the real GraphQL API.
Here is a complete list of one-to-one replacements made across the app:
Replaced getTasks()
from the mock store with the useGetTasksQuery()
Apollo hook.
Replaced getTaskById(id)
with useGetTaskQuery({ variables: { _id: id } })
.
Replaced createTask(name)
with the useCreateTaskMutation()
hook, passing the task name as mutation variables.
Replaced updateTask(id, updatedFields)
with useUpdateTaskMutation()
, supplying all fields through the variables
parameter.
Replaced deleteTask(id)
with the useDeleteTaskMutation()
hook and appropriate variables.
Each mutation now optionally refetches GetTasks
to ensure that the UI reflects the latest data after operations.
Previously, the mock API responded instantly, so loading indicators weren’t necessary. With real network requests in play, we implemented loading states across the app to ensure a smooth user experience:
EditTask
modal shows a loading indicator before task data is available.Alongside the main application, all tests and Storybook stories have been fully migrated to use the new GraphQL structure. This involved replacing mock store dependencies with Apollo mocks and ensuring all components behave consistently under real-world data flow, including loading and mutation states. The test suite now operates against realistic scenarios, and Storybook reflects the same GraphQL-driven architecture used in production.
This transition marks a major milestone:
Our MVP app is in a pretty good shape now. We have a working frontend and backend, but it only works locally on a development server.
To bring our app to life, we will have to set up our infrastructure to have the environment ready to deploy our app. This includes:
Here's how our timeline look like now: