9

Goal: I am designing a REST API that allows user to pass parameters on the query string for an HTTP GET request. Something like

http://fake.api.com/search?api-key=1235&term=car&rows=10

Implementation: on the server-side I have a model binder that takes those 3 parameters - api-key, term, and rows and converts them to a C# object so that my controller action method doesn't have to parse the query string. So the controller action method signature looks something like

public IHttpActionResult Get(RequestObject request)

Problem: what I am running into with Swagger is when it generates the documentation and the test harness, it is listing the input parameters as request.api-key, request.term, and request.rows. This is because JSON it is getting from the server is prefixing object name to these values. So when you try to use Swagger UI to do an HTTP GET request, it builds the URL like

http://fake.api.com/search?request.api-key=1235&request.term=car&request.rows=10

Which is an incorrect request for the server. Now I can easily make my model binder smarter to just ignore "request." part, but that seems like a backward way of fixing this problem.

Question: how can I customize JSON generated by Swashbuckle -> Swagger on the server side so that parameter names for this particular object aren't prefixed with the object name? I did look into both ISchemaFilter and IDocumentFilter that Swashbuckle extensibility API exposes, but I am not seeing a clean way to do this. May be it is possible, but an example would help in that case.

codelove
  • 1,396
  • 3
  • 17
  • 35

2 Answers2

8

Found a solution, which turned out to be the one thing I ignored - IOperationFilter. See https://github.com/domaindrivendev/Swashbuckle/issues/128 for details.

Update

Here is the code for the solution mentioned in the comment

public class IgnorePrefixParamsNameBeforeDot : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (operation.parameters != null)
        {
            foreach (Parameter param in operation.parameters.Where(p => p.name.Contains('.')))
            {
                param.name = param.name.SplitWithoutEmpty('.').Last();
            }
        }
    }
}
Egoulet
  • 63
  • 2
  • 5
codelove
  • 1,396
  • 3
  • 17
  • 35
  • can you point out which part of the provided link was of the interest? Did you have to implement the logic yourself (split the name by ".) or was it a built in swashbuckle that you just had to call in IOperationFilter? – ke3pup Sep 21 '15 at 03:21
  • I just used the IOperationFilter, and yes I split on "." manually, no magic there. More elegant way would be to decorate each property on that class and reflect and then parse these out, but I was pressed on time so went with the less elegant solution of parsing it. – codelove Nov 06 '15 at 14:37
  • Is SB now able to do this without this workaround? +1 for the `IOperationFilter` didn't even know there was such a thing lol. – Barak Apr 27 '17 at 07:41
0

I encountered a similar problem and found a somehow easy solution.

Although in my case it was for POST/PUT, it won't work for GET since GET doesn't have a body. Once I used the Attribute FromBody, Swagger started to render a proper JSON without prefixes. So in my case it looked something like that:

public IHttpActionResult Post([FromBody]RequestObject request)

It doesn't answer your question directly, but I was searching for a solution to a very similar swagger related problem, and that's what helped me, so I hope that it can be helpful for anyone.

Community
  • 1
  • 1
Maurice Klimek
  • 930
  • 5
  • 13
  • 48