Skip to content

Simple Approval ​

A typed durable approval with one operation and one work request.

dart
import 'package:vyuh_workflow_engine/vyuh_workflow_runtime.dart';
import 'package:vyuh_workflow_testkit/vyuh_workflow_testkit.dart';

final requestIdSchema = Schema<String>(
  name: 'requests.id',
  encode: (value) => value,
  decode: (value) => value! as String,
);

final requestSchema = Schema<Request>(
  name: 'requests.request',
  encode: (value) => value.toJson(),
  decode: Request.fromJson,
);

final resultSchema = Schema<Result>(
  name: 'requests.result',
  encode: (value) => value.toJson(),
  decode: Result.fromJson,
);

final failureSchema = Schema<RequestFailure>(
  name: 'requests.failure',
  encode: (value) => value.toJson(),
  decode: RequestFailure.fromJson,
);

final loadRequest = Operation<
  String,
  Request,
  RequestFailure
>(
  name: 'requests.load',
  version: 1,
  input: requestIdSchema,
  output: requestSchema,
  failure: failureSchema,
);

final decide = Work<Request, Approval>(
  name: 'requests.decide',
  version: 1,
  input: requestSchema,
  response: approvalCodec,
);

final requestApprovalDefinition = Workflow<
  String,
  Result,
  RequestFailure
>(
  code: 'requests.approval',
  version: 1,
  input: requestIdSchema,
  output: resultSchema,
  failure: failureSchema,
);

final requestApprovalHandler = requestApprovalDefinition.implement(
  fingerprint: 'requests.approval:v1',
  execute: (workflow, requestId) async {
    final request = await workflow.perform(
      loadRequest,
      requestId,
      id: 'load',
    );
    final decision = await workflow.request(
      decide,
      request,
      id: 'decide',
      title: 'Approve request',
      audience: const Audience(roleIds: ['managers']),
    );
    return decision.approved ? Result.approved() : Result.rejected();
  },
);

Drive It in Tests ​

dart
final test = WorkflowTestHarness(
  modules: [
    WorkflowModule(
      name: 'requests',
      workflows: [requestApprovalHandler],
      operations: [
        loadRequest.implement(
          (operation, id) => requestRepository.load(
            id,
            idempotencyKey: operation.context.idempotencyKey,
          ),
        ),
      ],
      work: [decide],
    ),
  ],
);

final run = await test.start(requestApprovalDefinition.ref, 'REQ-001');
await run.drain();
await run.respond(decide, Approval.approved());

final completed = await run.run;
expect(completed.status, WorkflowRunStatus.completed);
expect(
  requestApprovalHandler.exitOf(completed),
  isA<WorkflowSuccess<Result, RequestFailure>>(),
);

See Also ​