0

I'm creating a delete method in a DRF API, by passing parameters, but I don't know how to pass correctly an orientdb @rid.

I have a relationship in orientdb called "worksat", in OrientDB Studio i can see the @rid with the structure name like #:, i.e: "#33:1" is the @rid of a worksat relationship record.

enter image description here

So I need to pass that string in my DRF URL api relationship:

http://127.0.0.1:8000/api/oworksat/

But passing like:

http://127.0.0.1:8000/api/oworksat/#33:1

I see GET request, with the message below (I expect to see DELETE): Allow: GET, POST, HEAD, OPTIONS

If a pass a simple number:

http://127.0.0.1:8000/api/oworksat/1

Then I see DELETE request (obviously "1" doesn't exist):

HTTP 404 Not Found
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS

api.py:

class OWorksAtViewSet(viewsets.ModelViewSet):

    queryset = graph.oworksat.query()
    serializer_class = OWorksAtSerializer
    permission_classes = [
        permissions.AllowAny
    ]

    def destroy(self, request, *args, **kwargs):
        print ("destroy")
        import pdb;pdb.set_trace()

urls.py:

from django.conf.urls import include, url
from rest_framework import routers
from .api import (OWorksAtViewSet)
from rest_framework_swagger.views import get_swagger_view

router = routers.DefaultRouter()
router.register('api/oworksat', OWorksAtViewSet, 'oworksat')

schema_view = get_swagger_view(title='Swagger Documentation')

urlpatterns = [
    url(r'^swagger/$', schema_view)
]

urlpatterns += router.urls

The interesting thing is that by accesing from swagger api, in the DELETE method, if I a pass in the ID of the request "#33:1", it works, the api call to my destroy method and recieve in kwargs: kwargs = {'pk': '#33:1'}.

enter image description here

How can I reach that behavior from DRF api?

Edited: This is my temporal solution to implement my destroy method, but obviously this only works in Swagger UI, by passing @rid in the request.

from rest_framework import status
from rest_framework.response import Response
from core.pyorient_client import *

class OFriendsViewSet(viewsets.ModelViewSet):

    def destroy(self, request, *args, **kwargs):
        client = orientdbConnection()

        client.command("delete edge ofriends where @rid = '" + kwargs['pk'] + "'")

        return Response(status=status.HTTP_204_NO_CONTENT)
Manuel Carrero
  • 599
  • 1
  • 9
  • 29
  • Are you using any REST Client to make the request in the first scenario? Is it reaching the code? What is the error you are getting here? What's happening if you make a `DELETE` call with `/#33:1/`? – Dharanidhar Reddy Jun 16 '19 at 04:05
  • I'm using rest framework to make the request. By passing http://127.0.0.1:8000/api/oworksat/#33:1 the response is 200 but with GET method (so it's not reaching to the destroy method), I need that behaviour with DELETE method allowed – Manuel Carrero Jun 16 '19 at 04:09
  • So in your rest framework client, you couldn't able to see DELETE method right? – Dharanidhar Reddy Jun 16 '19 at 04:13
  • I can see it, but not by passing #33:1 in querystring, passing #33:1 I only see GET and POST method – Manuel Carrero Jun 16 '19 at 04:23

1 Answers1

1

I assume that when speaking about not being able to delete or see "Delete" button, you talk about Django Rest Framework browsable API.

Picture of DRF browsable API

When you access your API through DRF browsable API you get list of objects when you navigate to for example http://127.0.0.1:8000/api/oworksat/. This is the "list endpoint" and it doesn't support DELETE.

Delete button will be there when you access "detail endpoint" of single object, for example: http://127.0.0.1:8000/api/oworksat/123.

In your case however when you try to pass OrientDB @RID as object ID, browser thinks you want to get to list endpoint. This is because in urls everything after # is called fragment and this is not passed to server. So when you navigate to http://127.0.0.1:8000/api/oworksat/#1:23 browser actually requests page from http://127.0.0.1:8000/api/oworksat/ and thus gives you the list endpoint without delete button.

Why Swagger then works?

Swagger works probably because the request is not made the same way as browsers normally load pages. Swagger makes Ajax request to your API when you click the Delete button and thus the fragment part is not stripped from your url. Swagger also probably url encodes the value you type into UI and this would transform #1:22 to %231%3A22 and thus remove # which causes our problem. DRF then knows how to url decode the url automatically and ends up with correct looking ID.

Example of request Swagger probably does:

function deleteData(url, item) {
  return fetch(url + '/' + item, {
    method: 'DELETE',
    headers: {
      'Content-Type': 'application/json'
    }
  })
  .then(response => console.log(response.json()));
}

deleteData("http://127.0.0.1:8000/api/oworksat/", encodeURIComponent("#1:23"));

How to fix this?

Your API probably works correctly when @RID is url encoded and Ajax request is made. It just doesn't work with DRF browsable API.

However to make it nicer to work with for your users and also to make DRF Browsable API to work I would remove # from the ID's when they are serialized through your API. Users would then make requests to urls like http://127.0.0.1:8000/api/oworksat/1:23. Of course by doing it like this you would then need to prepend the client provided id with # before passing it to OrientDB query.

Menth
  • 388
  • 3
  • 5
  • Thanks for your detailed explanation, it is really appreciated. The problem is that I can't controll the way of rid is stored in OrientDB, because that field is the analogy of pk, so it's generated automatically, in consequence I can't serializated rid without # to work as you suggest. Anyway, I had to use a raw query in my OrientDB method (I edited my question) like below https://stackoverflow.com/a/56621592/6796652 but obviously, this solution only works in swagger UI – Manuel Carrero Aug 10 '19 at 00:46