ServiceStack.IntroSpec RFC

I’ve just pushed a new plugin that uses introspection to generate docs about all services registered in an AppHost. It’s available on github and nuget.

There’s still some functionality missing but we’re keen to get some feedback on the general approach and idea.

In a nutshell it generates a set of POCOs that contain the spec for all services. The idea is that these will provide a common starting point generate the output in a number of different specs (e.g. Swagger or RAML) to take advantage of existing tooling.

Implementation wise, it uses data from Metadata.OperationsMap as a starting point then uses reflection, custom abstract classes and standard XML documentation comments to further populate the POCOs. These can be viewed raw or massaged into a different format. There is Postman output available in the plugin now, with the plan to add more formats in the future as required. Full info in the readme of the repo.

This will be installed in all of the services within our microservices infrastructure and will allow each service to provide a set of POCOs that document the capabilities of that service. The next step is to create a site that will use these POCOs to stitch information from many disparate services in a single place. When used in conjunction with service discovery this will provide a neat way of finding out about the various operations available across multiple services.

2 Likes

Sounds like it would be a great feature if you’re able to provide a single comprehensive spec that can be used to generate all the different specs off from, it’s just that a lot of these specs are drowned in nuance and it may require too much additional metadata/effort from developers to be able to support each of them fully.

IMO the end goal for a lot of these specs is to generate a machine readable spec that you can use to generate a typed client from, whereas the Add ServiceStack Reference approach skips trying to target an interim spec and generates the types in the native language directly which can be used in conjunction with their respective typed Service Client to provide the same typed, productive development experience in all consumers preferred languages. i.e. We can provide a richer more integrated experience with cleaner models by going directly from C# -> Language, than going from C# -> abstract generic spec -> Language as we can take advantage of language features like Attributes/Annotations and enable Interfaces/Protocols for a much cleaner more idiomatic and integrated experience which is my preferred approach. But the nice part about providing a spec is that it can take advantage of a generated UI as seen in Postman / Swagger plugins, so specs still provide value.

Yes, time will tell how difficult it is to shape it into the various specs but hopefully they won’t be too difficult to maintain!

I agree that the Add Service Reference is the optimal way to generate client. As part of the site that stitches these together we’re looking to have an “Add Service Reference” that uses service discovery to pull together DTOs from different services and present a client that is composed of DTOs from different services.

2 Likes

There are two primary motivators for the approach we have taken.

The first is to maintain the ‘add servicestack reference’ approach across a number of services but via a single uri reference point. Our recent PR for wildcard selection of dto dependent types will help us do this from a dedicated aggregation endpoint using a customised version of the nativetypesfeature and our discovery solution. In effect it will stitch together the nativetypes output from multiple services and pass this to the existing language code-gen’s to output a single file back to the client IDE but sourced from multiple services, making what we hope is the best use of what is already OOTB.

The second motivation is to use the tooling available in the spec ecosystems to generate usage documentation rather than typed clients, in particular the RAML community has some great options for the generation of code examples and sdks across numerous languages that we can use for presenting usage examples. By being able to convert the DTOs into different spec formats, we can pick the best tooling to selectively generate additional documentation.

Our ultimate goal is to have a single documentation site that both our customers and internal teams can access to learn, search and filter all of the available services we offer and to provide sufficient documentation and code samples so that they can effectively consume them.

We are unlikely to support every field of every spec format as we agree that the nuances of these, in particular the openAPI (formerly swagger) is a bit of a behemoth that wants to be the all encompassing solution. That said, we feel that RAML is more realistic and at least offers us a lot of value

We have also tried to make the enrichers extensible for alternative or additional sources for documentation and the conversion from a set of populated DTO’s should allow others to implement existing or bespoke formatting for any current or future specification formats.

1 Like

Also I should mention (and I hope wont overlap too much with efforts here) is that I eventually plan to develop a customizable (i.e. brandable) API docs plugin that I’d like to replace the Swagger plugin with (as I don’t like the complex rolling spec it has become) with the focus on being able to interact with the Services in a UI and provide sections showing how different clients can call each Service in their language of choice e.g. in C#/F#/VB.NET/Swift/Java/Kotlin/TypeScript. It wont be providing any additional specs, just api docs and auto generated pages for each Service providing instructions on calling each Service with the users preferred language, ideally I’d like it to make it interactive and be able to execute the services on the page, e.g. using JS/Ajax to call the Service and display the results in the page.

I don’t expect to use any more of the annotations than what Swagger Plugin uses, but if you need more attributes for your spec than what’s already available let me know and I’ll add it to ServiceStack.Interfaces so people can add it to their DTO’s without sacrificing the reusability of the ServiceModel.dll on the client.

Also not sure if you’re aware of the naming conventions but we’re using ServiceStack.Api.* to categorize metadata provider packages, e.g:

There’s also the community contributed:

Maybe you wanted to follow a similar naming convention for this?

Sounds good, I think there is an opportunity to collaborate so we don’t waste effort on overlap as you say.

We have similar ambitions around branding and interaction with the addition of a dto cart style functionality to pick and mix dto’s from a range of services and pass this back to the add service reference functionality for lang gen but this could just as easily work against a single app host to provide a good ux around filtering dto’s to generate reference code for.

Open to any ideas and whilst we are happy to support our efforts as community addons if there is value to you in adopting or transferring any or parts of our repos to core, we would be happy to do so.

regarding the naming conventions, we did consider following this convention but decided against it for a couple of reasons.

the first being that we plan to offer alternative implementations of the same specs and those names are already taken by others ‘postman’ and swagger (1.0) being two examples.

Secondly we wanted to differentiate specs built from our base DTO’s in ServiceStack.IntroSpec package to allow other additional packages ServiceStack.IntroSpec.Swagger and ServiceStack.IntroSpec.Raml to be built on top of them. We felt this would ultimately be less confusing for package consumers.

Open to discuss this one further though.

Cool, open to code/concept reuse and collaboration where possible but it doesn’t look like I’ll be able to start on this until after we’ve upgraded to .NET 4.5 (first release after Aug 1st) and .NET Core is officially released and we’ve added support for it - which isn’t clear when it’ll be released (i.e. with tooling and guarantees they wont break the surface area) and how long it will take to add support for it. So we’re a long ways off starting on this, but just wanted to mention it here as it’s something I’ve always wanted to add to provide more value around and make Add ServiceStack Reference more accessible.

Not sure if it’s applicable but I’ll most likely be creating any advanced Interactive UI in React, e.g. similar way to how ServiceStack.Admin AutoQuery Viewer was developed, e.g. bundled with jspm and all resources embedded in the .dll.

Yep makes sense to use a shorter package name if you plan to add an ecosystem of additional plugins around it.

Also what does the “Intro” part represent? just Introductory Specs or something else? I’m personally for as shorter name as possible myself so I’d probably have gone for ServiceStack.Specs.* myself. (or with the category ServiceStack.Api.Specs.*)

Ok, whilst we are focused on how our plugins add value to our own projects, ultimately it would be best to provide something useful to the wider community to gain more collaboration and support around, so if you are able to advise us in certain areas, we can probably find the best way forward to satisfy both.

The naming was voted for internally so democracy won out! :wink:

It’s a pun on introspection and specification as the primary focus of the plugin was to abstract the introspection aspect of building DTO definitions away from individual/multiple implementations of specification formats.

1 Like

FYI Our current enricher sources are documented here, as we develop the next spec after postman, likely RAML 1.0, we will see if additional attribute requirements surface so we’ll let you know.

It is worth highlighting that we only really see the generation of specs as a means to utilise the existing tooling available as further ‘enrichers’ for our DTOs rather than generate a UI.

For the UI we will likely use the introspec DTO’s but we have no prior experience with building React.

Don’t know if I understand fully, but are you saying that the output of the introspec plugin is to generate the spec and that you wont be building a UI yourself, but instead leverage the existing UI’s built around the specs?

Would the UI be in the ServiceStack.IntroSpecs.Swagger plugin like we’re doing with the Swagger plugin atm, or are you expecting them to use their own Swagger UI?

I don’t understand it fully either! :smiley:

Each spec specific plugin will actually have 3 roles.

  1. Provide enrichment for our DTO’s via spec tooling, DTOs > Spec > ToolingEnrichers > Enriched DTOs
  2. Provide the raw spec format
  3. Embed any spec specific UI, like swaggerUI as you mentioned

so a swagger plugin could use any swagger based tooling that inputs a swagger spec and outputs something a swaggerenricher will parse. The raw swagger spec for anyone requiring this to use and the embedded swaggerUI to consume the raw swagger spec.

Our own UI will be another plugin ServiceStack.IntroSpec.[NameIsSecretRightNow] that just uses the DTO’s and any enrichers from the other plugins installed (role no 1) again with an embedded UI which we will build

Clear as mud?

I think that makes sense, I’d probably recommend using a convention for the UI so it’s easily discoverable, e.g:

  • ServiceStack.IntroSpec.Swagger - spec
  • ServiceStack.IntroSpec.Swagger.UI - UI, depends on spec package

Basically if users wont both spec and swagger UI (most would) they’d only need to install the UI package above and it could install both.

sure, could split ui’s to separate packages

the routing conventions will be /spec/{format}/{version?}/{ui?}

so

/spec - our DTO’s (add .format or ?contentType=json as needed
/spec/summary - overview for filtering info (categories, tags, request dto names)
/spec/postman - no real UI or enrichment so included OOTB rather than separate plugin
/spec/raml - defaults to latest version (1.0)
/spec/raml/0.8 - version specific
/spec/raml/ui - embedded UI using latest spec version (if UI applicable to format)

1 Like