Modelling API requests with Statecharts
Statecharts are a very useful tool for modelling complex workflows in your application.
XState is a full-featured JavaScript library, for working with statecharts and finite state machines.
Here’s how to model an API request in XState, using an invoked promise. It’s a little intimidating, but I walk through the important part below.
import axios from 'axios'
import { Machine, interpret } from 'xstate'
const getUser = id =>
axios.get(`/api/users/${id}`).then(response => response.data)
const config = {
id: 'example',
initial: 'idle',
context: { userId: 123 },
states: {
idle: {
on: { GET_USER: 'loading' },
},
loading: {
invoke: {
id: 'getUser',
src: (context, event) => getUser(context.userId),
onDone: {
target: 'success',
actions: (context, event) => console.log(event.data),
},
onError: {
target: 'failure',
actions: (context, event) => console.error(event.data),
},
},
},
success: { type: 'final' },
failure: { type: 'final' },
},
}
const machine = Machine(config)
const service = intepret(machine)
service
.onTransition(state => console.log(state.value))
.start()
.send('GET_USER')
The bit that matters
This is where the real action takes place:
invoke: {
src: (context, event) => getUser(context.userId)
}
When the statechart enters the loading
state, we immediately:
- Retrieve the
userId
from the statechartcontext
object - Call the
getUser
function, passing it the user ID.
The getUser
function returns a promise. XState automatically runs the onDone
transition when the promise resolves. If the promise is rejected, XState runs the onError
transition. In both cases, we can access the value returned by the promise via the event.data
property.
Sign up for my newsletter
A monthly round-up of blog posts, projects, and internet oddments.