Django-rest-framework + React-Admin : URL Backslash issue

Viewed 1597

I have a django rest api that implements viewsets as highlighted below.

class SubjectViewSet(viewsets.ModelViewSet):
    pagination_class = ContentRangeHeaderPagination
    queryset = Subject.objects.all()
    serializer_class = SubjectSerializer

Similarly, my frontend is based on react-admin here

import React from 'react';
import { Admin, Resource } from 'react-admin';
import simpleRestProvider from 'ra-data-simple-rest';
import { NonIndividualList, NonIndividualCreate, NonIndividualEdit} from './subjects';

const App = () => (<Admin dataProvider=simpleRestProvider('http://localhost:8000/api/v1/coreapp')}>

<Resource name="subject" title="Non-Individuals" list={NonIndividualList} 
create={NonIndividualCreate} edit={NonIndividualEdit}/>
</Admin>);
export default App;

In my rest server, under settings.py I have the following settings

APPEND_SLASH = False

Finally, my app/urls.py looks like this

router = DefaultRouter()
router.register(r'api/v1/coreapp/subject', views.SubjectViewSet)

urlpatterns = [(r'^', include(router.urls)),]

Question:

From postman, I can comfortably crud the endpoint

However, my react-admin client doesnot append a trailing slash

Instead, Http-actions Create/Put send the requests to url. Notice the missing trailing backslash?

http://localhost:8000/api/v1/coreapp/subject

I have tried to,

1- Set the Append_Slash = True 2- Added a / to the resource name, which simply appends two backslash

<Resource name="subject/"/>

http://localhost:8000/api/v1/coreapp/subject//2

for PUT, notice the additional backslash.

Bottom line is, my server accepts requests whenever they have a trailing backslash.

My react-admin app doesnot append the backslash on requests. Please SO, advise a brother :-)

4 Answers

@gildas-garcia

I followed your answer and as much as it made sense, the issue arose once again. When a request is sent the / is added at the end of the URL var after the query parameters have been appended

Desired URL (add a backslash before the ?)

http://localhost:8000/api/ps/nonindividual/?filter=%7B%7D&range=%5B0%2C9%5D&sort=%5B%22id%22%2C%22DESC%22%5D

When i follow your answer i get(backslash added at the end of the complete URL)

http://localhost:8000/api/ps/nonindividual?filter=%7B%7D&range=%5B0%2C9%5D&sort=%5B%22id%22%2C%22DESC%22%5D/

Moving forward, I opted to find the indexOf the ? in the URL and added the backslash at that index

const httpClient = (url, options = {}) => {

    var pos = url.indexOf('?');
    var b = "/";
    var _url = [url.slice(0, pos), b, url.slice(pos)].join('');

    //url = url + '/';
    return fetchUtils.fetchJson(_url, options);
}

const dataProvider = simpleRestProvider('http://localhost:8000/api/v1/coreapp', httpClient)


const App = () => (    
    <Admin dataProvider={dataProvider}
    <Resource name="subject" list={SubjectList} create={SubjectCreate} edit={SubjectEdit}/>
    </Admin>);

    export default App;

By default the URLs created by DefaultRouter are appended with a trailing slash. This behavior can be modified by setting the trailing_slash argument to False when instantiating the router. For example:

router = DefaultRouter(trailing_slash=False)

That's the job of your dataProvider to transform the request in the shape expected by your backend and to use the correct url.

In your case, you'll have to customize the httpClient as explained in the dataProvider documentation:

import { fetchUtils, Admin, Resource } from 'react-admin';
import simpleRestProvider from 'ra-data-simple-rest';

const httpClient = (url, options = {}) => {
    let finalUrl = `${url}/`;
    return fetchUtils.fetchJson(finalUrl, options);
}
const dataProvider = simpleRestProvider('http://localhost:3000', httpClient);
  • One solution may be using special dataProvider which is written for DRF. Here you can find it
  • Also, you when you are specifying URL route append slash at the end:

    urlpatterns = [ path('rolls/', SomeListView.as_view()),]

Related