bpmnServer / bpmn-server

BPMN 2.0 server for Node.js , providing modeling, execution, persistence and monitoring for Workflow. along with sample UI. Intended to be developers workbench for BPMN 2.0
MIT License
186 stars 48 forks source link

NestJs Integration #130

Closed kstan79 closed 1 year ago

kstan79 commented 1 year ago

So far I'd tested integrate with nestjs and using openapi. it work smoothly, below is example of controller, service class, and swagger-ui result, it work as expected!

//controller
import { Controller, Get,Post,Req,Param} from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  //get all workflow
  @Get('/')
  getWorkflows() {
    return this.appService.getPendingWorkflows();
  }
  //create workflow
  @Post('/:workflow')
  postStart(@Param('workflow') workflow:string) {
    return this.appService.startWorkflow(workflow);
  }
  // others required endpoint
  //get /:workflow/:id  //fetch info
  //put /:workflow/:id  //update info
  //post/:workflow/:id/:taskId  //invoke {user:xxx}
  //...
}
// service class
import { Injectable,Logger } from '@nestjs/common';
import {BPMNServer} from 'bpmn-server'
import {configuration} from './configuration'

@Injectable()
export class AppService {
  private readonly logger = new Logger();

  bpmnServer:BPMNServer
  constructor(){
    this.bpmnServer = new BPMNServer(configuration)
  }

  async startWorkflow(workflow:string){
    const result =  await this.bpmnServer.engine.start(workflow);        
    return {
      id: result.id,
      data:result.getData('id'),
      status: result.status
    }
  }
  async getPendingWorkflows(){
    const tmp:any[] = await this.bpmnServer.dataStore.findInstances({
      status:'running',
    },'summary')

    const result = tmp.map((proc)=>({
      id: proc.id,
      workflowname: proc.name,
      startedAt: proc.startedAt,
      tasks :proc.items
              .filter((task)=>task.status=='wait')
              .map((task)=>({
                id:task.id,
                type:task.type,
                assignee:task.assignee,
                candidateUsers:task.candidateUsers,
                candidateGroups:task.candidateGroups
              }))
    }))

    return result
  }
}

sample

I'm curious so far any documentation of upload bpmn file? I don't know the process of upload file until the engine support the new definition.

ralphhanna commented 1 year ago

Thank you for your great contribution, this looks very good.

I am working on a new API still under development, can release soon that will help you alot

below is an example of calls:


    let api = new Request(server, { userId: 'user1', userGroups:['Owner','Others'],  });

    let items = await api.data.findItems({ "items.candidateGroups": "Owner", "items.candidateUsers": "User1" });
    items = await api.findItems({ "$or": [{ "items.candidateGroups": "Owner" }, { "items.candidateUsers": "User1" }]});

    console.log(api.user);
    api = new Request(server, APIUser.SystemUser());
    console.log(api.user);

    let response = await api.engine.start('Buy Used Car');

    response = await api.engine.invoke({id: response.id , "items.elementId": 'task_Buy' });
    var src = await  api.model.getModel('Buy Used Car');
    var list = await api.model.listModels({name:'deleteLater'});

    await api.model.saveModel('deleteLater', src, null);
    await api.model.deleteModel('deleteLater');
    list = await api.model.listModels({});

Your feedback on the above example is highly appreciated

BTW, in your call of getPendingWorkflows, you can use findItems instead of findInstances it uses MongoDB faster

kstan79 commented 1 year ago

thanks reply, i mean so far any reference of upload bpmn file? Is it I put the file in defination folder it will auto generate new model, or i need to read file content then run await api.model.saveModel('deleteLater', src, null);?

I saw there is svg property too, I shall update manually in model collection?

thanks getPendingWorkflows advise!

ralphhanna commented 1 year ago

auto generate uses the saveModel function But you can use saveModel for files outside of definitions folder or when you keep all your models in DB. The last parameter is the svg

     async saveModel(name, source,svg) 
ralphhanna commented 1 year ago

Can you please share a sample project for nestJs, OpenAPI and swagger I will integrate into next release Thanks very much

kstan79 commented 1 year ago

Will do, also will write setup documentation for you

kstan79 commented 1 year ago

you may refer minimal example here: https://github.com/kstan79/nestjs-bpmn-server

kstan79 commented 1 year ago

since you will integrate with nestjs at next release, i think it is better i wait your latest release, Im worry it will have huge impact. By the way, I have more complex working example with:

  1. keycloak integration
  2. swagger-ui perform api-key/oauth2 autorization
  3. some working middleware, decorators, practise of request scope user.context
  4. api-request logging
  5. mongodb transaction (if neccessary)

if you need help in nestjs kindly let me know, we can create discord channel for this project, good for public discussion. since this project community not only 1-2 person now