While designing the API with with the team a suggestion was forwarded in regards to some complex query parameters that we sent which need to be encoded as objects, arrays of objects, etc. Suppose I have a route GET /resource/ and I want to apply a set of filters directly in the query params. The object literal structure of this filter would be something like
filter: {
field1: {
contains: 'value',
notin: ['value2', 'value3']
},
field2: {
greaterThan: 10
}
}
Encoding this in the url, via a query string parser such as the qs node module that express.js uses internally, would be cheap on the backend. However 1) The generated url is very hard to read, if a client wants to connect with the API he would need to use an encoding library and 2) I don't think I ever encountered the use of query params like this, it looks a little bit of overengineered and I'm not sure how used it is and if it is really safe.
The example above would yield query params such as:
GET /resource/?field1%5Bcontains%5D=value&field1%5Bnotin%5D%5B0%5D=value2&field1%5Bnotin%5D%5B1%5D=value3&field2%5BgreaterThan%5D=10
Does this practice of sending url query parameters that happen to be complex objects have some standards or best practices?
We implemented a different solution for filtering, when the list of possible parameters was very long. We ended up doing it in two steps, posting the filter and returning a filter ID. The filter ID could then be used in the GET query.
We had trouble finding any best practices for this.
Related
books?:
type: array
items:
enum: [a,b,c,d]
Let's say I want to give a bad request whenever b,c come together. Eg:
[a,b,c,d] -> invalid request
[a,b,c] -> invalid request
[b,c] -> invalid
In short, if a request has both b & c together, can 400 be displayed using RAML ?
You can declare different types of valid combinations and then use them as possible input types.
Something like:
types:
validCombinationA:
type: array
items:
enum:
- a
- b
- d
validCombinationB:
type: array
items:
enum:
- a
- c
- d
And then:
books?:
type: validCombinationA | validCombinationB
That way is going to fail whenever you use an invalid combination.
If the valid combinations are static and the probability of new future values is small, then it's not a big deal using this approach but if that's not the case, you will need to create X number of types for each valid combination.
Maybe it worths a thought of consideration look for other possibilities for your use case (eg: with OAS that can be done with the usage of elements such as oneOf, anyOf, allOf, not).
If the validation is quite simple, then I'd prefer to do it that way instead of using the Validation Module or something else inside a flow given that probably has an impact on performance (do some quick tests to verify it).
That's not possible. RAML is not expected to be used to define data validation. RAML only define validations of types and the structure of requests. You need to implement that kind of rule in the implementation of the API. In this particular case it seems that you are using Mule to implement the API. Inside the Mule application project you need to perform the validation in the flows.
I consider myself that 0 is not a good thing to do when returning information from an API
e.g.
{
userId: int|null
}
I have a colleague that insists in that userId should be 0 or -1, but that forces a system to know that the 0 means "not set", instead of null which is universally known as not set.
The same happens with string params, like logoUrl. However, in this case I think it is acceptable to have an empty string instead of null if the variable is not set or was unset.
Is there bibliography, standards, etc, that I can refer to?
I'm not aware of any standard around that, but the way I take those kind of decisions is by thinking about the way consumer services would read this response, the goal being to provide a very smooth and clean consuming workflow. This exercise can even be transformed into a documentation for your API consumers.
In your case, instead of returning a null/0 field, I would simply remove that field altogether when it's empty and let the consumers explicitly mark that field as optional in the model they use to deserialize this response.
In that way, they'll explicitly have to deal with those optional fields, than relying on the API to always provide a value for them.
I have a GET API url something like: /api/countries.
I want to search from it using multiple parameters like name& code... For that, I will do /api/countries?name=pak&code=92
But what if I want to use OR in url params e.g. /api/countries?name=pakORcode=92
If you use OR as you have shown in your question then it will not work (name will contain the value pakORcode=92). If this is something that you would consider doing then you could use explode to split into key-value pairs around each OR.
You could maybe also have a third variable, method. You could set this to either AND or OR, then you'd know what method to use?
Hope this helps
What you describe is not a regular API call.
you can solve this in 2 ways
Create the logic in your controller where you implement the or statement
Implement the ODATA REST protocol.
I would prefer ODATA. Entity framework has support for this and you can even implement this on your own created lists.
In ODATA you can use filter expressions:
filter=name eq 610 or code eq 615
https://msdn.microsoft.com/en-us/library/hh169248(v=nav.90).aspx
I'd like to be able to specify a string, let's say
NSString * pathPattern = /api/elements/:id/subelement/:type
and call a simple function
[pathPattern build:#{#":id" => id, #"subelement" => subelement}]
to generate the URL path.
Obviously I can build a simple category to do this, but does something exist that handles such things in a generic way, and maybe has additional useful features for this kind of thing that I haven't thought of at this time?
Yes, RestKit already injects parameters into path patterns. Internally it uses SOCKit to perform this parameterisation.
It actually uses exactly the format you have in the question and where the parameter names match keys on the supplied object for mapping.
The path pattern can also be used during response mapping to take values back out of the request URL.
I'm writing an API using Django, and I'm running into some issues around returning data that isn't stored in the database directly, or in other cases organized differently than the database schema.
In particular, given a particular data request, I want to add a field of computed data to my model before I serialize and return it. However, if I just add the field to the model, the built-in serializer (I'm using json) ignores it, presumably because it's getting the list of fields from the model definition.
I could write my own serializer, but what a pain. Or I guess I could run model_to_dict, then serialize the dict instead of the model. Anyone have any better ideas?
Here's what the code vaguely looks like right now:
squidlets = Squidlet.objects.filter(stuff)
for i in range(len(squidlets)):
squidlets[i].newfield = do_some_computation(squid)
return HttpResponse(json_serializer.serialize(squidlets,ensure_ascii=False),
'text/json')
But newfield ain't in the returned json.
i think you should serialize using simple json.. and it doent have to be a queryset... to escape it as json also use marksafe
from django.utils.safestring import mark_safe
from django.utils import simplejson
simplejson.dumps(mark_safe(your_data_structure))
I went with the dict solution, which turned out to be fairly clean.
Here's what the code looks like:
from django.forms.models import model_to_dict
squiddicts = []
squidlets = Squidlet.objects.filter(stuff)
for i in range(len(squidlets)):
squiddict = model_to_dict(squidlets[i])
squiddict["newfield"] = do_some_computation(squidlets[i])
squiddicts.append(squiddict)
return HttpResponse(simplejson.dumps(squiddicts,ensure_ascii=False),
'text/json')
This is maybe slightly more verbose than necessary but I think it's clearer this way.
This does still feel somewhat unsatisfying, but seems to work just fine.