OData / odata.net

ODataLib: Open Data Protocol - .NET Libraries and Frameworks
https://docs.microsoft.com/odata
Other
687 stars 349 forks source link

Documentation support like Swagger? #1214

Open antgustech opened 6 years ago

antgustech commented 6 years ago

I was wondering if it is possible to integrate OData controllers with Swagger or similar services to provide API documentation? There is an old unmaintained project for this but I can't get it to work. Nevertheless I would not want to use that in production anyway. Is there official support for Swagger incomming?

biaol-odata commented 6 years ago

@madansr7 Can you take a look at whether we can add any documentation?

TehWardy commented 6 years ago

Yeh i had this issue ... I created a base ODataController that inherited from the one MS has written in the framework and added a "GetMetadata()" method that returned an object that looks much like an MVC MetadataContainer for that type / endpoint.

Having done that I was then able to append custom extended metadata to the call using reflection or db calls / both.

It would be nice to have a built in option to do things like "generate a form" on a web page for the basic CRUD calls though. I've been experimenting with Kendo UI for this but i'm pretty sure that there's a smarter way than my approach.

xuzhg commented 6 years ago

@Baxtex @TehWardy Did you have a chance to take a look the e2e test cases in Web API OData for Swagger: https://github.com/OData/WebApi/tree/master/test/E2ETest/Microsoft.Test.E2E.AspNet.OData/Swagger

Anyway, there is another common library used to covert Edm (CSDL) to Open API. See https://github.com/microsoft/openapi.net.OData

TehWardy commented 6 years ago

Wonderfully elegant solutions … Certainly less code in the user code than I have (by a few lines) … But where I have already quite "heavy" controllers in a large model I needed a means to pull just the meta for a single type in the model on it's own … Describing the whole model is a considerable hit on page load times when you have to build a complex client.

I now have (on the JS side in the browser) a means to say …

var ds = dataSource.get("Model/Type", args);
$("someJQuerySelector").kendoGrid(ds);

… makes building things like grids trivial but also keeps the metadata based load to minimum.

My understanding was that swagger worked like that too … but is extensible, querying the ODataEdmModel like that though … feels like a big job (construct, grab the one bit you need, throw away) on every request … so I just used MVC and a bit of reflection (maybe slower, not sure, but certainly lighter in load) like this …

    public class EntityODataController<T> : CoreODataController
    {
        protected IService<T> Service { get; private set; }

        public EntityODataController(IService<T> service, ApiMetadataProvider metaProvider) : base(metaProvider, auth)
        {
            Service = service;
        }

        [HttpGet]
        public virtual IHttpActionResult GetMetadata()
        {
            return Ok(new MetadataContainer(MetaProvider.GetMetadataForType(null, typeof(T))));
        }

ApiMetadataProvider inherits from MVC's built in "DataAnnotationsModelMetadataProvider" so I get the model information directly from the data annotations and reflection of a type.

There's up sides and down sides to this … Ups:

  1. It seems pretty fast and is customisable on a per type basis
  2. I literally expose the raw metadata by inspecting the type itself
  3. I don't have to take on any new dependencies
  4. I can cache the reflection work / complete response if need be
  5. I'm looking in to "dynamic controllers" where based on something like "current user" I modify the model to expose sets that they have access to (like subscription levels).
  6. I'm also thinking I can do db queries to tie in user docs / test plans directly to the metadata.

Downs:

  1. It uses reflection (although gut feeling I bet that all these methods do)
  2. It's possible for me to expose stuff that doesn't exist in the OData model which could tell clients wrong information

I've been making my entities "smart" a bit "OOP like" so if I have an Invoice entity type I create an approve method on it and then I can map that in OData. I use the type info to determine what the method needs and i'm careful to expose on the controller "with rules applied" that the objects interface looks like.

It requires a strict set of coding standards but means I do a ton of work by convention.

Grauenwolf commented 3 years ago

Here is a Stack Overflow post showing how to add OData parameters to Swagger. https://stackoverflow.com/a/69842284/5274

It would be nice if this was built-in, but I don't know if that's possible given how this example works.