Skip to content

Instantly share code, notes, and snippets.

@markbjerke
Last active June 10, 2020 17:49
Show Gist options
  • Save markbjerke/c280a113d6fafd91a28290d4de13a4e5 to your computer and use it in GitHub Desktop.
Save markbjerke/c280a113d6fafd91a28290d4de13a4e5 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
// Available variables:
// - Machine
// - interpret
// - assign
// - send
// - sendParent
// - spawn
// - raise
// - actions
// - XState (all XState exports)
class TXTimeout extends Error {}
const requestId = 'req_id';
const options = {};
const timeoutMs = 10 * 1000;
const url = 'https://jsonplaceholder.typicode.com/todos/1'
const txrequest = Machine({
id: 'txrequest',
context: {
request: {
url,
options,
timeoutMs
},
response: undefined
},
initial: 'pending',
states: {
pending: {
on: {
FETCH: 'loading'
}
},
loading: {
invoke: {
id: `${requestId}`,
src: (context, event) => new Promise( async(resolve, reject) => {
const timeout = setTimeout(() => {didTimeout = true; reject(new TXTimeout(requestId))}, timeoutMs);
fetch(url, options).then((response) => {
clearTimeout(timeout);
if(!didTimeOut) {
resolve(response);
}
})
.catch((error) => { // only rejects if request wasn't sent; e.g. security/cors
if(!didTimeOut)
reject(error);
});
}),
onDone: {
target: 'response',
actions: assign((context, event) => {
context.response = event.response
})
},
onError: [
{ target: 'rejected.timeout', cond: 'isTimeout' },
{ target: 'rejected.notsent' }
]
},
on: {
CANCEL: 'pending'
}
},
response: { // transient state; evaluates the response and moves to resolved...
on: {
'': [
{ target: 'resolved.http_404', cond: 'isHttp404' },
{ target: 'resolved.http_401', cond: 'isHttp401' },
{ target: 'resolved.invalidStatusCode', cond: 'isInvalidStatusCode' },
{ target: 'resolved.success' }
]
}
},
resolved: {
states: {
success: {
type: 'final',
meta: {
message: 'The request succeeded!'
}
},
http_404: {
type: 'final',
meta: {
message: `The resource ${url} was not found.`
}
},
http_401: {
type: 'final',
meta: {
message: `The request failed authentication.`
}
},
invalidStatusCode: {
type: 'final',
meta: {
message: `The request failed, http status is not in range 200-299 inclusive.`
}
}
}
},
rejected: {
states: {
timeout: {
final: true,
meta: {
message: 'The request timed out.'
}
},
notsent: {
type: 'final',
meta: {
message: 'The request failed to send.'
}
}
}
}
}
},
{
guards: {
isTimeout: (context, event) => {
return event instanceof TXTimeout;
},
isHttp404: (context, event) => {
return context.response ? 404 === context.response.status : false;
},
isHttp401: (context, event) => {
return 401 === context.response ? context.response.status : false;
},
isInvalidStatusCode: (context, event) => {
return context.response ? !context.response.status.ok : false;
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment