Remember how you have to set up a whole bunch of infrastructure locally just to be able to independently work on the frontend part of your Jamstack project? If you’re tired of doing so, maybe this short write-up on how to replace the infrastructure with code-based dependency mocks is just up your alley.
In a nutshell
The basic idea is to have inline mocks of remote services in your frontend code which will be compiled while running your project locally but will not be bundled with your production code. The separation is achieved via additional Typescript path mappings and module resolving in Webpack.
In the past I’ve typically set up a local server to mock my remote API, but have always had some problems with that approach:
- it added more dependencies to the project
- it required an extra step during initialization
- it was prone to errors when the API changed
- it needed a lot of manual work to adjust to API changes
- I always seemed to forget to write some proxy rule in the frontend framework’s configuration which required a restart of the local dev server
Frontend-based code mocks, on the other hand, offer a number of benefits to speed up development:
- compile time errors resulting from unreflected API changes
- fine grained control over every aspect of the mocks
- automatic code rebuild
- the mocks are directly available in the tests – no need to do custom remote API mocking/stubbing
That being said, the old setup can imho still be very helpful in some circumstances, especially for projects where Typescript and Webpack are not available.
I’m assuming that you are using the following:
- UI with Typescript support
- Webpack as bundler
- HTTP remote REST API
To illustrate both mocking techniques I’ll be using a demo Vue.js project created with the official CLI. Note that you can use any modern frontend framework with Typescript and Webpack support.
The demo project is available in this github repository.
For the remote API part I’ll be using Kitsu’s free anime API to display a random anime content.
The resulting “application” can be found under https://ts-mocked-remote-api.codecentric.rocks/.
A blast from the (not so distant) past
A typical implementation for a REST-based remote API mock can be found in the
express-mock folder in the repository. I have used very similar ones for mocking GraphQL based APIs but they generally required even more work to get right so I’ll omit describing them and their many pitfalls for brevity.
Just a quick overview of what’s needed for this to work:
- local express server
- local HTTP proxy
The idea here being that you start the local express server which will mimic the behavior of your backend server. The HTTP proxy will be the router between your local development server for the frontend and the mocking backend server.
To try it out head over to
express-mock and run
npm run mock:api which will fire up the express server listening on port 4100 and await to serve mock data. A quick check with a command like
curl "localhost:4100/trending/anime?limit=2" should show if the mocked server is working.
Now all that’s left is a HTTP proxy rerouting the requests from the frontend development server to the backend mock. Usually the rule looks something like this:
localhost:8080/remote-api -> localhost:4100. As this example is using Vue.js with the Vue CLI the way to wire this is via a dev proxy – as described in the official documentation.
The HTTP proxy configuration for the example used here looks like this:
And that’s it – now we should be able to develop the frontend part of our Jamstack app independently from the real backend. Oh wait, this setup was just to show how the process used to look like – the interesting part is yet to come 🙁
Mocking with Typescript and Webpack
You’ve read the gist of the idea – now it’s time to talk about the implementation. Let’s divide it into a 4-step-process:
- Implement mock services
- Add path mapping in Typescript’s compiler options
- Setup Webpack to omit the mocks from the production build
- (Optional) setup test harness with the custom alias/path mapping
Show me the mocked service
Coding the mocked services is pretty much straightforward, since there is an interface we can implement. I’ll be using faker.js for producing semantically and syntactically correct fake data. Also, just for fun, there is a random delay in the response. You can go wild and add exceptions, faulty data and so on to appear randomly in order to make it feel more like working with a remote API.
Configuring the Typescript compiler
A new path mapping is needed in the Typescript configuration in order to be able to pinpoint which imports are to be replaced later on in the bundling phase by Webpack.
A service import will then look like this:
Also note that I am using a facade for convenient class/interface exporting.
Now let’s configure module resolving in webpack. The idea behind it being to explicitly specify the location of the imported code modules based on the current environment.
Configuring the test harness
Last but not least the test harness should be updated to be able to follow the custom path mapping as defined in the
tsconfig.json file. I opted for using jest so the module mapper should only be updated. Everything else can be inherited from the base configuration:
With the above jest configuration, importing the remote services will always include the mocked version:
And that’s it – now your project will use the mocked implementation of the remote service when working locally and the real one in the production build! But don’t take my word for it – check out the whole example in this github repository.