-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* adds base project * remove unnecessary imports * update readme with launch instructions. * update models with JS shorthand * rename directory and update imports
- Loading branch information
1 parent
52900a0
commit 7d5eebf
Showing
12 changed files
with
2,073 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
lerna-debug.log* | ||
.pnpm-debug.log* | ||
|
||
# Diagnostic reports (https://nodejs.org/api/report.html) | ||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
*.pid.lock | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
*.lcov | ||
|
||
# nyc test coverage | ||
.nyc_output | ||
|
||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# Bower dependency directory (https://bower.io/) | ||
bower_components | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (https://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directories | ||
node_modules/ | ||
jspm_packages/ | ||
|
||
# Snowpack dependency directory (https://snowpack.dev/) | ||
web_modules/ | ||
|
||
# TypeScript cache | ||
*.tsbuildinfo | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional eslint cache | ||
.eslintcache | ||
|
||
# Optional stylelint cache | ||
.stylelintcache | ||
|
||
# Microbundle cache | ||
.rpt2_cache/ | ||
.rts2_cache_cjs/ | ||
.rts2_cache_es/ | ||
.rts2_cache_umd/ | ||
|
||
# Optional REPL history | ||
.node_repl_history | ||
|
||
# Output of 'npm pack' | ||
*.tgz | ||
|
||
# Yarn Integrity file | ||
.yarn-integrity | ||
|
||
# dotenv environment variable files | ||
.env | ||
.env.development.local | ||
.env.test.local | ||
.env.production.local | ||
.env.local | ||
|
||
# parcel-bundler cache (https://parceljs.org/) | ||
.cache | ||
.parcel-cache | ||
|
||
# Next.js build output | ||
.next | ||
out | ||
|
||
# Nuxt.js build / generate output | ||
.nuxt | ||
dist | ||
|
||
# Gatsby files | ||
.cache/ | ||
# Comment in the public line in if your project uses Gatsby and not Next.js | ||
# https://nextjs.org/blog/next-9-1#public-directory-support | ||
# public | ||
|
||
# vuepress build output | ||
.vuepress/dist | ||
|
||
# vuepress v2.x temp and cache directory | ||
.temp | ||
.cache | ||
|
||
# Docusaurus cache and generated files | ||
.docusaurus | ||
|
||
# Serverless directories | ||
.serverless/ | ||
|
||
# FuseBox cache | ||
.fusebox/ | ||
|
||
# DynamoDB Local files | ||
.dynamodb/ | ||
|
||
# TernJS port file | ||
.tern-port | ||
|
||
# Stores VSCode versions used for testing VSCode extensions | ||
.vscode-test | ||
|
||
# yarn v2 | ||
.yarn/cache | ||
.yarn/unplugged | ||
.yarn/build-state.yml | ||
.yarn/install-state.gz | ||
.pnp.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"tabWidth": 2, | ||
"useTabs": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Express Credit Check Workflow | ||
|
||
This is a simple workflow engine built with: | ||
|
||
- XState v5 | ||
- TypeScript | ||
- Express | ||
|
||
This is a modified version of the express-workflow project that shows how to implement state hydration in the `actorService.ts` file. | ||
It also uses a more complex machine with guards, actions, and parallel states configured. | ||
|
||
**NOTE**: This project is _not_ production-ready and is intended for educational purposes. | ||
|
||
## Usage | ||
|
||
[MongoDB](https://www.mongodb.com/docs/manual/administration/install-community/) should be configured with a database named `creditCheck`. | ||
|
||
We recommend installing the [MongoDB Compass app](https://www.mongodb.com/products/tools/compass) to view the contents of your database while you run this project. | ||
|
||
Add the connection string to the DB client in the `actorService.ts` file by updating this line: | ||
|
||
```typescript | ||
const uri = "<your mongo uri here>/creditCheck"; | ||
``` | ||
|
||
```bash | ||
pnpm install | ||
pnpm start | ||
``` | ||
|
||
## Endpoints | ||
|
||
### POST `/workflows` | ||
|
||
Creates a new workflow instance. | ||
|
||
```bash | ||
curl -X POST http://localhost:4242/workflows | ||
``` | ||
|
||
Example response: | ||
`201 - Created` | ||
|
||
```json | ||
{ | ||
{"message":"New worflow created successfully","workflowId":"uzkjyy"} | ||
} | ||
``` | ||
|
||
### POST `/workflows/:id` | ||
|
||
`200 - OK` | ||
|
||
Sends an event to a workflow instance. | ||
|
||
```bash | ||
# Replace :id with the workflow ID; e.g. http://localhost:4242/workflows/7ky252 | ||
# the body should be JSON | ||
curl -X POST http://localhost:4242/workflows/:id -d '{"type": "Submit", "SSN": "123456789", "lastName": "Bauman", "firstName": "Gavin"}' -H "Content-Type: application/json" | ||
``` | ||
|
||
### GET `/workflows/:id` | ||
|
||
Gets the current state of a workflow instance. | ||
|
||
```bash | ||
curl -X GET http://localhost:4242/workflows/:id | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import bodyParser from "body-parser"; | ||
import { | ||
collections, | ||
getDurableActor, | ||
initDbConnection, | ||
} from "./services/actorService"; | ||
import express from "express"; | ||
import { creditCheckMachine } from "./machine"; | ||
|
||
const app = express(); | ||
|
||
app.use(bodyParser.json()); | ||
|
||
// Endpoint to start a new workflow instance | ||
// - Generates a unique ID for the actor | ||
// - Starts the actor | ||
// - Persists the actor state | ||
// - Returns a 201-Created code with the actor ID in the response | ||
app.post("/workflows", async (_req, res) => { | ||
console.log("starting new workflow..."); | ||
try { | ||
// Create a new actor and get its ID | ||
const { workflowId } = await getDurableActor({ | ||
machine: creditCheckMachine, | ||
}); | ||
res | ||
.status(201) | ||
.json({ message: "New worflow created successfully", workflowId }); | ||
} catch (err) { | ||
console.log(err); | ||
res.status(500).send("Error starting workflow. Details: " + err); | ||
} | ||
}); | ||
|
||
// Endpoint to send events to an existing workflow instance | ||
// - Gets the actor ID from request params | ||
// - Gets the persisted state for that actor | ||
// - Starts the actor with the persisted state | ||
// - Sends the event from the request body to the actor | ||
// - Persists the updated state | ||
// - Returns the updated state in the response | ||
app.post("/workflows/:workflowId", async (req, res) => { | ||
const { workflowId } = req.params; | ||
const event = req.body; | ||
|
||
try { | ||
const { actor } = await getDurableActor({ | ||
machine: creditCheckMachine, | ||
workflowId, | ||
}); | ||
actor.send(event); | ||
} catch (err) { | ||
// note: you can (and should!) create custom errors to handle different scenarios and return different status codes | ||
console.log(err); | ||
res.status(500).send("Error sending event. Details: " + err); | ||
} | ||
|
||
res | ||
.status(200) | ||
.send( | ||
"Event received. Issue a GET request to see the current workflow state" | ||
); | ||
}); | ||
|
||
// Endpoint to get the current state of an existing workflow instance | ||
// - Gets the actor ID from request params | ||
// - Gets the persisted state for that actor | ||
// - Returns the persisted state in the response | ||
app.get("/workflows/:workflowId", async (req, res) => { | ||
const { workflowId } = req.params; | ||
const persistedState = await collections.machineStates?.findOne({ | ||
workflowId, | ||
}); | ||
|
||
if (!persistedState) { | ||
return res.status(404).send("Workflow state not found"); | ||
} | ||
|
||
res.json(persistedState); | ||
}); | ||
|
||
app.get("/", (_, res) => { | ||
res.send(` | ||
<html> | ||
<body style="font-family: sans-serif;"> | ||
<h1>Express Workflow</h1> | ||
<p>Start a new workflow instance:</p> | ||
<pre>curl -X POST http://localhost:4242/workflows</pre> | ||
<p>Send an event to a workflow instance:</p> | ||
<pre>curl -X POST http://localhost:4242/workflows/:workflowId -d '{"type":"TIMER"}'</pre> | ||
<p>Get the current state of a workflow instance:</p> | ||
<pre>curl -X GET http://localhost:4242/workflows/:workflowId</pre> | ||
</body> | ||
</html> | ||
`); | ||
}); | ||
|
||
// Connect to the DB and start the server | ||
initDbConnection().then(() => { | ||
app.listen(4242, () => { | ||
console.log("Server listening on port 4242"); | ||
}); | ||
}); |
Oops, something went wrong.