django-rest-swagger how to document the APIs - django-rest-framework

I am now using DRS for my simple django REST APIs and although its not perfect, it has been a great library so far. But having a few issues
I am using
django-rest-swagger==2.0.3
And my api-doc looks like this
Issue #1: I can't find a way to add some documentation, I tried putting YAML under my class based viewset action methods, not working. Put docstring under ViewSet class directly, no luck. Then I saw that in the latest DRS release, 2.0 change mentioned YAML docstring has been deprecated.
So how do I provide something like
1. Endpoint short description
2. parameter description and probably a sample format
Issue #2: How do I specify which parameter is mandatory.
For example, I have an action in my UserViewSet
#detail_route(methods=['post'], url_path='set-password')
#AssertInRequestBody(['password'])
def set_password(self, request, pk):
"""
set user password
"""
user = User.objects.get(pk=pk)
json_data = get_json_data(request)
user.set_password(json_data['password'])
user.save()
return DefaultResponse(_('Successfully set password for user %s'
% user.email), status.HTTP_200_OK)
And I want it to be a POST operation and there will be a password in the request body. I can't figure out a way to document that.
This applies to other operations, I guess right now DRS is simply looking at the model definition and serializer definition to determine which parameter is mandatory, which doesn't quite make sense to me.
I feel that DRS should provide some sort of decorators so that we can easily add corresponding documentation to an action method.
But maybe I am wrong, please help if DRS does provide such functionalities.
Thanks,

May be this is so late, but just for some help, this doc explains django rest swagger 2 integration step by step:
Django Rest Swagger 2 comprehensive documentation

Since you are doing a post, to add the end point short description this is what I would do
def set_password(self, request, pk):
"""
create:
set user password
"""
...
Or in your UserViewSet class:
class UserViewSet(...)
"""
set_password:
set user password
"""
That may answer question 1

Related

Endpoint grouping/collection using Iris + Swag

How can I group the endpoints by Party ? Which declaration/annotation comment should I use ? I'm having this:
I need the endpoints to be grouped by something like "Books", "Catalogs" and so on,... not one unique unnamed "default" group. How can I achieve that?
PS: My problem is similar to this link, but I'm using Iris-Go, and this plug-in.
UPDATE1
.json file
Iris-go uses gin-swagger/swaggo under the hood. In Swagger to get endpoints grouped it should be enough to add tags (see https://swagger.io/docs/specification/grouping-operations-with-tags/).
In swaggo you need to use #Tags declarative parameter in endpoint comment like this:
// #Tags: Books
See swaggo example code with #Tags here.

Django REST Framework: Exclude a specific route while retain standard ViewSets

I am using Django REST Framework (DRF) for my API. In particular, I have set up several routes using the ModelViewSet, without much additional coding. In particular, I have a route like
/api/v1/collection/<key>
From all the possible keys, I do need to block one specific key, say special. Any request with any HTTP verb to /api/v1/collection/special should result in a HTTP 404 error.
I can think of two approaches:
Override some method on the ViewSet hierarchy. Which one?
In urls.py, set up a higher-precedence URL route that intercepts this URL, like path("collection/special", view=<404View>, name="collection-exception"). Does this make sense? What would be the appropriate exception view to route to?
What is the recommended approach? Any of the above, or something else?
If you are using the ModelViewSet then you should overwrite the get_queryset() method. If key value is wrong then raise the Exception otherwise return the queryset:
from rest_framework.exceptions import NotFound
class MyModelViewSet(viewsets.ModelViewSet):
# ...
def get_queryset(self):
key = self.kwargs.get("key")
if key == "special":
raise NotFound()
return MyModel.objecs.filter(pk=key)

Google Places API setFields AND getDetails

The google places api docs clearly state: "IMPORTANT: To avoid paying for data that you don't need, be sure to use Autocomplete.setFields() to specify only the place data that you will use." But then when I'm calling the getDetails() method (see in generic-y form below), I'm specifying my fields, which is what setFields() sets.
I THINK I'm basically setting them via the getDetails() method, but given the caution exercised in the docs, I also don't want to surprise anyone with extra costs besides what we need. I've tried to find a clear answer in the docs, but I haven't found one. I'm hoping someone here knows from experience or has better luck with the docs. Thanks!
const placesService = new google.maps.places.PlacesService(myField);
placesService.getDetails(
{
fields: ['address_components'],
placeId: result.place_id,
sessionToken: token,
},
details => this.updateMethod(details.address_components),
);
Autocomplete.setFields is used when implementing Places Autocomplete Widget which will constrain the succeeding Places Details request to specific fields only when a user selects a place from the suggestions. Check out the example here.
However, as for your given sample code, I can see that you are directly using Places Service to get the details of a place given a Place ID and not from the Autocomplete Widget suggestions. With this, you can just set the fields in the request parameter of the getDetails(request, callback) method which is what you have correctly done in your code. See this example.
Hope this helps!

Writing data to model from POST request (Odoo 9.0)

I have the following model:
class LibraryBook(models.Model):
_name = 'library.book'
name = fields.Char('Title', required=True)
date_release = fields.Date("Release Date")
author_ids = fields.Many2many("res.partner", string="Authors")
I'm new to Odoo and trying to understand the basics of how to save data to my model from a POST request like the following
curl -i -X POST --data "name=Odoo%20-%20Much%20Mystery,%20Wow&author_id=Doge" http://0.0.0.0:8069/test
I found a way doing this by setting the csrf parameter in my controller to false like so:
[...]
#http.route('/test', type='http', auth='public',methods=['POST'], website=True, csrf=False)
def test(self, **kwargs):
record = request.env['library.book'].sudo()
record.create(kwargs)
I'm wondering now if there is a way to avoid setting csrf=false since I've read that it's a bad idea to do so in general. Also, what would I need to get rid of that .sudo()? Not setting csrf=false leads to a 400 BAD REQUEST with Invalid CSRF token. Removing sudo() leads to a 500 INTERNAL SERVER ERROR. In Odoo Development Cookbook it says in one example with auth='none'
Lack of a user is also why we have to sudo() all our calls to model methods in the example code
Assuming I would expect a POST request from an API, is it possible to associate it with a user so I don't have to sudo()?
I would very much appreciate any clarification on this.
UPDATE
So I just found this (line 817):
if the form is accessed by an external third party (e.g. REST API endpoint, payment gateway callback) you will need to disable CSRF
protection (and implement your own protection if necessary) by
passing the csrf=False parameter to the route decorator.
which I guess leaves only one question open, regarding sudo.
SUDO()
creates a new environment with the provided user set, uses the administrator if none is provided (to bypass access rights/rules in safe contexts), returns a copy of the recordset it is called on using the new environment:
Odoo does not allow public users to create, update, delete a record.
If we want to create a record from the public users then we need to create a record with the sudo().
Create record object as administrator
request.env['library.book'].sudo().create(vals)
I hope this may help you.
for more information you can navigate to following links :
https://www.odoo.com/documentation/9.0/reference/orm.html
Thanks

Django Rest Framework Nested Serializer required=False error

In DRF v3.1, I have a nested serializer much like the one detailed in the docs - http://www.django-rest-framework.org/api-guide/serializers/#dealing-with-nested-objects
class SerializerA(serializers.Serializer):
details = DetailsSerializer(required=False)
However, when trying to use this serializer and not supplying the details, I receive the following:
{u'details': [u'This field may not be null.']}
This seems incorrect given the docs?
Has anyone else come across this or can verify this as a bug?
Ok, so Kevin Browns comment is correct. I needed to add allow_null=True.
class SerializerA(serializers.Serializer):
details = DetailsSerializer(required=False, allow_null=True)
The reason for this is that having required=False allows the field details to be absent from the data when constructing the serializer.
e.g.
s = SerializerA(data={})
whereas allow_null permits the the param to be specified but be null.
e.g.
s = SerializerA(data={'details': None})
This opens up another issue with DRF Browsable API, but i'll ask that in a different question.

Resources