SparkleXrm icon indicating copy to clipboard operation
SparkleXrm copied to clipboard

✨Custom API support

Open ramontebar opened this issue 3 years ago • 10 comments

Hi @scottdurow,

Happy Xmas and almost Happy New Year 🎉

It would be great if spkl (Task Runner) could be extended to support the new Custom API.

In a similar way that today you can deploy plugins and custom workflow assemblies, you could deploy a plugin and associate it to a Custom API record.

Thanks Ramon

ramontebar avatar Dec 30 '20 12:12 ramontebar

Hi @ramontebar - Happy New Year to you too!

Do you think the plugin type metadata should define the whole API entity (with parameters etc) - when custom apis are created they need to be associated with a solution so I'm wondering if it would be that helpful - what is your specific use case? Is it just being able to register a plugin type without any steps so that it can be referenced by a custom api definition? Thanks!

scottdurow avatar Dec 30 '20 20:12 scottdurow

Thanks @scottdurow for the quick reply.

These are some ideas I am thinking of. I'll try to list them from the basic to the most "nice-to-have" one:

  1. Register a plugin type without any step. You can do this today using the same CrmPluginRegistration constructor used for custom work activities. It works the first time, but if you try to update it after the initial registration, it fails once the plugin type has been associated with a Custom API record. So you need to disassociate it, update the plugin and associate it again. Hopefully, this is just a Microsoft bug. So I guess this basic support is pretty much there.
  2. Associate plugin type with Custom API record. spkl would try to find any Custom API records mentioned in the CrmPluginRegistration decorator and associate the plugin type automatically.
  3. Create Custom API records programmatically. If a Custom API mentioned in the CrmPluginRegistration decorator is not found (as it doesn't exist in the environment), it would be created and associated with the current plugin type. The decorator could also define the input and output parameters that would create the corresponding Custom API Request Parameters and Response Properties respectively
  4. Earlybound generator to consider Custom API records. This scenario is kind of the opposite of the previous one (3). In this case, the Custom API record has already been created (e.g. using the UI). Similar to how actions are generated, spkl would generate plugin classes with input and output parameters based on the corresponding Custom API Request Parameters and Response Properties respectively.

Please let me know if these don't make sense. I also don't want to over complicate it, especially considering how Jim has describes the ability to create Custom API in the solution customisations file. I guess another way is just making sure the customisations are unpacked with the source code and developers can update the XML in the customisations file.

ramontebar avatar Dec 31 '20 15:12 ramontebar

Hi @ramontebar - all really good points.

  1. This is the priority I think, since as you say it will fail at the moment. CustomApis register on a 'For Internal Use Only' stage but still look like a plugin step. spkl tries to remove it - which fails - a check is just needed so these internal use only registrations are kept.

  2. Definitely think this is a good one. So perhaps a registration of: [CrmPluginRegistration("spkl_CustomApiTest")] spkl would then try and register the plugin against the custom API with a unique name of that given. If no custom API is found, then an error would be thrown.

  3. I am in two minds about this. Really, custom APIs are no different to Custom Actions - and the definitions of those are setup in the solution manager. Whilst we could create metadata on the plugin class to define the custom api registration - I don't know if it will be used all that much?

  4. Definitely like this one - it starts to move into the territory of a 'Plugin Base Class' type implementation. We could also take a different tack if we went with 3 above - in that the reverse would be true - you declaratively create a class with inputs/outputs - add metadata, and the custom api would be created in accordance with you code - instead of your code being created from the api defintion. This would be similar to how Azure Functions work.

scottdurow avatar Jan 18 '21 23:01 scottdurow

@ramontebar if you get a moment maybe you could try out https://github.com/scottdurow/SparkleXrm/pull/404

scottdurow avatar Jan 20 '21 05:01 scottdurow

Hi @scottdurow! Great work, thanks for reviewing my feedback and introducing this first change so quickly.

I have run some tests and it looks good 🙌

I have posted this article to give you an idea of what I have tested:

https://ramontebar.net/2021/01/20/deploy-custom-api-using-spkl/

I was not sure how you were expecting me to try it, but basically, I got the code from this commit #404, compile it, take the release assemblies and put it into my own project overwriting the Nuget package references 😺

ramontebar avatar Jan 20 '21 18:01 ramontebar

Perfect @ramontebar - thank you!

This will be merged into the next beta in the next week.

What do you think about the CustomApi definition part? David Rivard's XrmToolBox plugin is good for managing the api definition until we get a better experience in the solution designer. If we could define the api in the plugin it would allow us to define the behaviour and the schema all in one place - but is it really of benefit? Having a class to make it easier to access inputs/outputs could be of benefit - and if we have that - then it would make sense to allow generation of the api definition as well?

scottdurow avatar Jan 20 '21 18:01 scottdurow

Oh, I hadn't had the chance yet to try David and Jonas tools. I have just done it and they are very handy.

Regarding the Custom API definition, I see what you meant, so the above option 4 would be more useful, I agree. You mentioned a plugin base class. That could be one approach. The other approach would be an independent class representing the action and its parameters, like how actions or entities are generated. I am more inclined to the latter because it would allow people to keep their current plugin base class and it feels like more independent.

What do you think @scottdurow?

ramontebar avatar Jan 21 '21 09:01 ramontebar

This is released to NuGet in https://github.com/scottdurow/SparkleXrm/releases/tag/spkl-v1.0.441

scottdurow avatar Jan 30 '21 01:01 scottdurow

@ramontebar Yes- I agree - there would just need to be some code somewhere that allowed serialising/deserialising the pipeline input/output parameters. Maybe it could go in the CrmPluginRegistrationAttribute.cs file since that's already in people's projects?

scottdurow avatar Jan 30 '21 01:01 scottdurow

Thanks @scottdurow for publishing the NuGet version!

Good question regarding where to put that code. I guess there are two scenarios here:

  1. a plugin that actually implements the logic for a Custom API
  2. a different plugin or a custom workflow activity (as long as they are alive 🤭) that executes a Custom API using early-bound types.

The second scenario 2. is already covered by CrmSvcUtil. So it would be great if scenario 1. could reuse the types already generated by CrmSvcUtil. The parameters are the same type, Microsoft.Xrm.Sdk.ParameterCollection. It is a pity that OrganizationRequest doesn't give us a constructor to initialise their properties automatically given a ParameterCollection. I guess that would have actually helped us.

So, where that code should go? CrmPluginRegistrationAttribute.cs would be fine, although this piece of logic doesn't feel like follows the same type of elements you have put it there so far. I guess CrmPluginRegistrationAttribute.cs could then be renamed to something more generic later on if it carries on growing.

ramontebar avatar Feb 04 '21 18:02 ramontebar