Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Freeform query string parameters #349

Closed
TroyMass opened this issue Apr 29, 2015 · 30 comments
Closed

Freeform query string parameters #349

TroyMass opened this issue Apr 29, 2015 · 30 comments

Comments

@TroyMass
Copy link

Original Issue: swagger-api/swagger-ui#1185

Some API are designed to allow for some known parameters as well as any freeform parameters to be applied.

For example: say I have an API for users. A user has a firstName, lastName, userName, email, and many other fields. I want to create an API endpoint that would allow for me to do any combinations of GET /users?firstName=joe&lastName=smith and return matches for this. Instead of defining 2^N endpoints for every combination of the fields on the object, I define one endpoint which accepts any number of parameters and filters results based on it.

To do this (using Java - Spring MVC)

    @Autowired
    HttpServletRequest request;

    @RequestMapping("/users", method = RequestMethod.GET)
    @ApiOperation(value = "Find users filtered", freeformParams = true)
    public List<User> findUsersFiltered(
        @RequestParam(value = "limit") @ApiParam(value = "Limit size") final String limit) {
        Map<String, String[]> filters = request.getParameterMap();
        // do stuff with the filters...
    }

As you can see, I added a freeformParams = true which would tell swagger-ui that additional query params are allowed. On swagger-ui, this would add boxes where you could type the query string key and value. These params are in addition to any existing parameters defined by @ApiParam

Key Value
limit 10
firstName joe
lastName smith
add another value

This would generate a request such as GET /users?limit=10&firstName=joe&lastName=smith

@rhazegh
Copy link

rhazegh commented May 18, 2015

+1 for this

@SgtHotshot
Copy link

+1. Really running into this issue right now

@who
Copy link

who commented Oct 1, 2015

+1

1 similar comment
@corleonis
Copy link

+1

@unleashed
Copy link

Related #380

@harobed
Copy link

harobed commented Jan 2, 2016

+1

2 similar comments
@tlusk
Copy link

tlusk commented Jan 20, 2016

+1

@ghost
Copy link

ghost commented Jan 20, 2016

+1

@SimplicityGuy
Copy link

+1 for me as well. This also needs the flexibility of allowing different types of freeform queries. Path queries are ok, but what about sending over a query as json or GraphQL? This feature should allow sending freeform queries in either format.

@webron
Copy link
Member

webron commented Jan 20, 2016

Sending out JSON as a query parameter is conceptually wrong, but assuming you only want to say 'this is a string' and not expect to define that as a JSON object, I'm ok with that.

@SimplicityGuy
Copy link

Not as a query string, agreed, that's totally wrong.

But what about as a required header?

@webron
Copy link
Member

webron commented Jan 21, 2016

A JSON as anything other than a body or a specific type of form param (multipart) wouldn't make much sense. REST APIs still rely on HTTP, and with HTTP you can say that the payload is formatted in a given type (Accept) or multipart body parameters (aka, form parameters) will allow you do define the specific mime type for each part. There is nothing, however, that allows you to define how a query/header/path parameters should be serialized. You can't say whether it's JSON, XML, YAML or any other format. So, free-form strings? Sure. Explicit types - that's a bit of a problem.

@SimplicityGuy
Copy link

Indeed.

From a API design perspective, this sort of query can also be handled with a POST (with the query expressed through json), and the response is the same data as would be provided in the original). Just a different design decision providing the same results.

As an example, the JIRA API provides such functionality. There is some freeform-ness to the POST data, especially when querying for issues... many optional fields, restrictions on values in fields, etc.

@webron
Copy link
Member

webron commented Jan 21, 2016

But the freeform-ness in a body payload already exists in the spec...

@SimplicityGuy
Copy link

Yep, just calling out another way to solve this for those who have the flexibility to do it another way. Just stating the obvious I guess.

Sent from my iPhone

On Jan 20, 2016, at 5:09 PM, Ron notifications@github.com wrote:

But the freeform-ness in a body payload already exists in the spec...


Reply to this email directly or view it on GitHub.

@paivaric
Copy link

paivaric commented Feb 5, 2016

+1

@jharmn
Copy link
Contributor

jharmn commented Feb 5, 2016

Interesting concept @MassTroy. My initial reaction is why wouldn't you simply define all possible parameters explicitly (not in unique combinations)? It seems like a rare use case where every single field is queryable, usually there's some exceptions (I feel compassion for those who do have to perform this at scale).
Beyond that, how would you deal with nested values, i.e. {"name": {"first": "Jason", "last": "Harmon"}} with that query format? Something like ?name/first=Jason?
I ask because in order for tooling to infer the potential query parameters from the response model, nested values would need to be accommodated. Also, any implied pairings (as you were implicitly describing) would not be inferrable...which kind of leads me back to simply defining all of the possible fields in explicit parameters.
If you needed to document the unique combinations which are queryable, this would have to be made explicit.

Just trying to flesh this one out, as it seems like there's a pretty big interest level.

@TroyMass
Copy link
Author

TroyMass commented Feb 5, 2016

Yes this is pretty edge case, but critical if you are building dynamic APIs with flexible schemas behind them. We use JSONpath syntax for nested attributes. So in your example it would be ?name.first=Jason. Slashes are too much trouble in URLs

@dilipkrish
Copy link
Contributor

Since the example in spring based, thought I'd chime in with my 2 cents.

Spring supports this notion of ModelAttributes so the above example could be modeled as a Criteria object. Loosely somewhat like this (example in c# for brevity)

class Criteria {
     public Name name {get; set;}
}
class Name {
     public string firstName {get; set;}
     public string lastName {get; set;}
}

This is implicitly interpreted like described by @MassTroy when we define the endpoint like this

@RequestMapping("/users", method = RequestMethod.GET)
    @ApiOperation(value = "Find users filtered", freeformParams = true)
    public List<User> findUsersFiltered(
        @ModelAttribute Criteria) {
        // do stuff with the filters...
    }

This is nice because it makes the query parameters explicit i.e. we define parameters name.firstNameand name.lastName.

Now when we don't want/care to be explicit. we can define the operations like this

@RequestMapping("/users", method = RequestMethod.GET)
    @ApiOperation(value = "Find users filtered", freeformParams = true)
    public List<User> findUsersFiltered(
        @RequestParam Map<String, String> params) { // currently supported in springfox ONLY as form variables (not query string)
        // do stuff with the filters...
    }

This will render a parameter that is Map. Which in essence is really freeform query parameters as we need it.

So my take would be that the spec supports this as it is currently is without any change. Now support for this might be behind in swagger-core, and definitely in springfox, but there needs to be no change to spec IMO.

@jharmn
Copy link
Contributor

jharmn commented Feb 5, 2016

@dilipkrish I agree that it's doable in the spec now...just define all of the parameters (including nested with JSONPath). Clearly this could be made easier with codegen solutions, to build all possible parameters from the response model (i.e. tooling issue).
Parameter dependencies are a whole other scope of issue, and likely too complex to include anyways.

@webron
Copy link
Member

webron commented Feb 13, 2016

I always assumed the request here is just to also allow wildcard query parameters (in name). The type of the parameter would either be automatically wildcard too or one specific type. Unlike other parameter types, for query parameters it may make sense in some cases.

@jasonh-n-austin - there's actually a ticket for parameter inter dependencies #256 - and I tend to agree it may be too complex to support.

@OMarohn
Copy link

OMarohn commented May 12, 2016

+1

i also need a practical way for a kind of query by example functionality for my Entities.

My implementation uses the uriInfo.getQueryParameters(); to get the Parameters.

So far so good. But unfortunately i can't annotate the Parameters for Swagger because the spec force me to use the jax-rs Annotations. That's no option for me because in max. a can have Entities with more than 254 Attributes -> QueryParams. And that's more than a Methode in Java can handle.

IMHO there are two more Options:

1.) Put the Query in the GET Body -> afaik thats against the Spec (-> Mr. Fielding: https://groups.yahoo.com/neo/groups/rest-discuss/conversations/messages/9962 )

2.) Create an own Query and use onely one Parameter like ?query="attr=test&attr2=test...
Uncool to reinvent the wheel

Or to allow to uses the Swagger Annotation without the jax-rs Annotations. (incl. the parameter - Metadata from the jax-rs annotation)

@webron
Copy link
Member

webron commented May 19, 2016

Parent: #565

@edudar
Copy link

edudar commented May 20, 2016

My use-case is a bit different from described above but still somewhat falls into freeFormParams category. I do allow prefixed parameters on couple methods of my API. I know that any parameter with name that starts with data_ (similar to HTML's data- attributes) should be taken in to account.

@draakhan
Copy link

draakhan commented Jun 2, 2016

I also have a very similar case as OP.

My case is implemention of an endpoint conforming FHIR search standard. Such an endpoint is able to process a large set of query parameters with modifiers (e.g. param:modifier=value). In our Swagger-UI documentation we would like to have possibility to generate a text field where a user can provide a desired part of query params which will be appended as-is without any modification, url-escaping, etc. to a GET request query string.

I see this issue is part of #565 - do you know roughly when it will be addressed?

@dflock
Copy link

dflock commented Oct 13, 2016

I have a similar issue - our application provides a REST query interface to a NoSQL backend, which our (enterprise, on-prem) customers can fill with whatever data they want.

This means that we don't know the 'schema' - the field/key names - up front, so we couldn't hardcode all the possible combinations into the spec file, even if we wanted to.

These appear in the query URL as parameters to query on, with a prefix of data_ and a suffix for operator - e.g. ...&data_FirstName__eq=STRING:Brian... or ...&data_Weight__gte=70.0...

This sounds similar to @edudar and @draakhan , in that it's a little bit FHIR-like. My ideal solution would be more like #367 - but I think a freeform parameter could be made to work.

@fehguy
Copy link
Contributor

fehguy commented Feb 1, 2017

This has been added by #804

@prabhakaranm1411
Copy link

yes yes

@prabhakaranm1411
Copy link

+1 for this

yes yes

@ymallikarjunaa10
Copy link

@ApiOperation(value = "Find users filtered", freeformParams = true)

freeformParams is not present in ApiOperation. I am using springfox-swagger2.
and it downloads swagger-annotations-1.5.20.jar.. it does not have freeformParams property in ApiOperation.

Please tell me if i have to use different version of swagger.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests