Best practice for urls without trailing slash

I have a website in which I want my api nodes not end with trailing slashes. In my main urls.py I have

# urls.py
    path("api/", include("api.urls")),

And inside my api app I have my regular api nodes:

# api/urls.py
    path("", TemplateView.as_view(template_name="index.html")),
    path("runs", views.RunListView.as_view(), name="run-list"),
    ...

That will give me urls like /api/, /api/runs, etc. So far so good. But if I want my “root” app node also have no trailing slash, I would do:

# urls.py
    path("api", include("api.urls")),
# api/urls.py
    path("", TemplateView.as_view(template_name="index.html")),
    path("/runs", views.RunListView.as_view(), name="run-list"),
    ...

I now need to prepend a slash to all of my nodes inside the app! Is that right? Is that considered a good practice? Somehow it does not sound like a good practice to me. I’m more used to have paths of the type “my-path/” or “my-path” but never “/my-path”.

Please tell me if you have any experience on this and whether you think this pattern is common.

I can understand why you might not want a trailing slash on your url, but I’m not sure I understand why you would be concerned about a trailing slash on an earlier segment of the url.

path("api/", include("api.urls")),

Why is this an issue?

This is one of those situations in which I don’t really have a good answer to that, mainly because I’m not sure what other people do. My only motivation was to have this situation:

  • /api
  • /api/customers
  • /api/customers/5
  • etc

instead of

  • /api/ (This is the only with a slash)
  • /api/customers
  • /api/customers/5
  • etc

but maybe it’s just nitpicking?

If that’s really an issue, you could define it twice in your urlpatterns:

# urls.py
    path("api", TemplateView.as_view(template_name="index.html")),
    path("api/", include("api.urls")),

Yes, I guess that’s a reasonable compromise, although I think I’ll just stick to having api/. Thanks for your input, Ken.

I have a case against it being a non-issue.

URLs for the listings app:

# listings/urls.py
urlpatterns = [
    path("", views.listing_list, name="listing-list"),
    path("pretraga", views.ListingSearchView.as_view(), name="listing-search"),
    path("<int:pk>", views.ListingDetailView.as_view(), name="listing-detail"),
    
    # 4 Authentication & authorization
    path("postavka", login_required(views.ListingCreateView.as_view()), name="listing-create"),
    path("<int:pk>/izmena", login_required(views.ListingUpdateView.as_view()), name="listing-edit"),
    path("<int:pk>/brisanje", login_required(views.listing_delete), name="listing-delete"),
]

listings URLs are added to project URLs.

urlpatterns = [
    path("admin/", admin.site.urls),
    path("i18n/", include('django.conf.urls.i18n')),
    path("", include("auth2.urls")),
    path("oglasi/", include("listings.urls")),
    path("korisnici/", include("users.urls")),    
]

I’m currently on https://localhost:8000/oglasi/. Do you think that /oglasi/?strana=1 looks better than /oglasi?strana=1? I don’t think so. How do I make it the other way?

In fact, my initial motivation to have api endpoint not ending with a slash is the use case you present. I wanted to avoid the clashing /? (which I personally don’t like). But I see no other compromise than the one suggested above.