concentricsky / django-tastypie-swagger

An adapter to use swagger-ui with django-tastypie.
Other
132 stars 144 forks source link

"404 : NOT FOUND" of all resources on django 1.6.2 and tastypie 0.11.0 #59

Closed dcale closed 10 years ago

dcale commented 10 years ago

I tried to document my API with this package but I keep getting the following screen:

screen shot 2014-03-25 at 12 50 22

it looks like tastypie-swagger is not generating the correct schemas needed for swagger.

the resources all work fine besides that they cannot be documented.

johnraz commented 10 years ago

Hi @dcale , which version of tastypie-swagger are you using ? and can you provide your urls.py file ? Thanks

dcale commented 10 years ago

Sure, here the versions (if you need I can provide the full freeze): Django==1.6.2 django-tastypie==0.11.0 django-tastypie-swagger==0.1.2

here my urls.py:

from django.conf.urls import patterns, include, url
from django.conf.urls.static import static
from django.contrib import admin
from apps.letters.api import LetterResource,LayoutResource,TemplateResource,TemplateCategoryResource,SignatureResource,AttachmentResource
from tastypie.api import Api
from apps.letters import views
from PrintService import settings
from apps.persons.api import PersonResource
from apps.posts.api import PostResource
from vendor.ApiObjects.api import ApiUserResource, UserRegisterResource, ApiKeyResource, OwnedApiFileResource
from vendor.ApiObjects.views import fileUpload

admin.autodiscover()

v1_api = Api(api_name='v1')
v1_api.register(ApiUserResource())
v1_api.register(UserRegisterResource())
v1_api.register(ApiKeyResource())
v1_api.register(OwnedApiFileResource())

#letters
v1_api.register(TemplateCategoryResource())
v1_api.register(TemplateResource())
v1_api.register(LetterResource())
v1_api.register(LayoutResource())
v1_api.register(SignatureResource())
v1_api.register(AttachmentResource())

#persons
v1_api.register(PersonResource())

#posts
v1_api.register(PostResource())

urlpatterns = patterns('',
    url(r'^$', views.index, name='index'),
    url(r'^viewer/$', views.pdfViewer, name='PDF Viewer'),
    url(r'^letter/$', views.letterView, name='letterview'),

    url(r'^api/upload/', fileUpload, name='file_upload'),
    url(r'^admin/', include(admin.site.urls)),
    url(r'^api/', include(v1_api.urls)),

    url(r'^billing/', include("apps.finances.urls")),
    url(r'api/doc/', include('tastypie_swagger.urls', namespace='tastypie_swagger')),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
johnraz commented 10 years ago

Ok, did you set TASTYPIE_SWAGGER_API_MODULE = 'yourapp.urls.v1_api' in your settings ?

edit: also make sure to review the readme for the version 1.2, master branch has changed quite a bit.

dcale commented 10 years ago

Yes, but with my own "mainsite" (TASTYPIE_SWAGGER_API_MODULE = 'PrintService.urls.v1_api')

It somehow does discover the resources, but goes not further, because http://localhost:8000/api/doc/resources/ gives me the following:

{
"basePath": "http://localhost:8000/api/doc/schema/",
"apis": [
{
"path": "/apiKey"
},
{
"path": "/apiUser"
},
{
"path": "/attachment"
},
{
"path": "/layout"
},
{
"path": "/letter"
},
{
"path": "/ownedApiFile"
},
{
"path": "/person"
},
{
"path": "/post"
},
{
"path": "/register"
},
{
"path": "/signature"
},
{
"path": "/template"
},
{
"path": "/templateCategory"
}
],
"apiVersion": "0.1",
"swaggerVersion": "1.1"
}
johnraz commented 10 years ago

It's the expected output... It's probably and incompatibility between 1.2 and tastypie 0.11

Could you launch a django shell and give me the output of:

import PrintService.urls
path, attr = getattr(settings, 'TASTYPIE_SWAGGER_API_MODULE', None).rsplit('.', 1)
getattr(sys.modules[path], attr, None)._registry

Another option is to try with the latest master code, it's stable and has more feature, but you will need to change your settings a bit ;-)

johnraz commented 10 years ago

Ok I think I got it, you should put this line:

url(r'api/doc/', include('tastypie_swagger.urls', namespace='tastypie_swagger')),

in your main urls.py , not the one of your tastypie app... ;-)

dcale commented 10 years ago

This happens if I launch the django shell:

{'apiKey': <vendor.ApiObjects.api.ApiKeyResource object at 0x10dac11d0>, 'layout': <apps.letters.api.LayoutResource object at 0x10dac2490>, 'template': <apps.letters.api.TemplateResource object at 0x10dac1850>, 'apiUser': <vendor.ApiObjects.api.ApiUserResource object at 0x10dab3d90>, 'register': <vendor.ApiObjects.api.UserRegisterResource object at 0x10dac1090>, 'person': <apps.persons.api.PersonResource object at 0x10dac2c90>, 'attachment': <apps.letters.api.AttachmentResource object at 0x10dac2a10>, 'templateCategory': <apps.letters.api.TemplateCategoryResource object at 0x10dac1590>, 'signature': <apps.letters.api.SignatureResource object at 0x10dac2750>, 'letter': <apps.letters.api.LetterResource object at 0x10dac1c90>, 'post': <apps.posts.api.PostResource object at 0x10dac3110>, 'ownedApiFile': <vendor.ApiObjects.api.OwnedApiFileResource object at 0x10dac1310>}

And the line

url(r'api/doc/', include('tastypie_swagger.urls', namespace='tastypie_swagger')),

already is in my main urls file :S

johnraz commented 10 years ago

The code you pasted above shows that the tastypie_swagger.urls is imported in your app's urls.py not in your project's urls.py

johnraz commented 10 years ago

Actually, if you only have 1 urls.py and don't have a sub app for your api, you are doing it wrong.

You should have a directory structure like this:

project
 - project
  -- settings.py
  -- main_urls.py <-- imports api_app.urls AND tastypie_swagger.urls
 - api_app
  -- api_urls.py
dcale commented 10 years ago

Mhh ok, what I now did:

project
 - project
 -- settings.py
 -- urls.py <-- imports api.urls.v1_api AND tastypie_swagger.urls
 - apps
 -- api
 --- urls.py

project.urls:

from django.conf.urls import patterns, include, url
from django.conf.urls.static import static
from django.contrib import admin
from apps.letters import views
from PrintService import settings
from vendor.ApiObjects.views import fileUpload
from apps.api.urls import v1_api
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^$', views.index, name='index'),
    url(r'^viewer/$', views.pdfViewer, name='PDF Viewer'),
    url(r'^letter/$', views.letterView, name='letterview'),

    url(r'^api/upload/', fileUpload, name='file_upload'),
    url(r'^admin/', include(admin.site.urls)),
    url(r'^api/', include(v1_api.urls)),

    url(r'^billing/', include("apps.finances.urls")),
    url(r'api/doc/', include('tastypie_swagger.urls', namespace='tastypie_swagger')),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

apps.api.urls:

__author__ = 'Alessandro De Carli'
from apps.letters.api import LetterResource,LayoutResource,TemplateResource,TemplateCategoryResource,SignatureResource,AttachmentResource
from apps.persons.api import PersonResource
from apps.posts.api import PostResource
from vendor.ApiObjects.api import ApiUserResource, UserRegisterResource, ApiKeyResource, OwnedApiFileResource
from tastypie.api import Api

v1_api = Api(api_name='v1')
v1_api.register(ApiUserResource())
v1_api.register(UserRegisterResource())
v1_api.register(ApiKeyResource())
v1_api.register(OwnedApiFileResource())

#letters
v1_api.register(TemplateCategoryResource())
v1_api.register(TemplateResource())
v1_api.register(LetterResource())
v1_api.register(LayoutResource())
v1_api.register(SignatureResource())
v1_api.register(AttachmentResource())

#persons
v1_api.register(PersonResource())

#posts
v1_api.register(PostResource())

But I still have the same issue :(

johnraz commented 10 years ago

I just tested my dev project with 1.2 and 0.11, I did import urls as you just did and it works perfectly...

There is something wrong..

Could you try to add a breakpoint in tastypie_swagger/views.py , line 120 and see what this `not resource_name in self.tastypie_api._registry`` gives you ?

dcale commented 10 years ago

I did that now, and the findings: it never gets to that point. The schema view is never executed (even if I put some simple "print" they don't get executed), only the resource view on the other hand is executed properly.

I'm now pretty confused... Do I need to import the schema urls myself?

dcale commented 10 years ago

Ok, I now had a "major breakthrough". If I delete the trailing slash "/" from tasypie_swagger.urls

url(r'^schema/(?P<resource>\S+)/$', SchemaView.as_view()),

thus making it look like:

url(r'^schema/(?P<resource>\S+)$', SchemaView.as_view()),

Everything works as expected. Somehow the resource view presents all paths without trailing slash:

{
"basePath": "http://localhost:8000/api/doc/schema/",
"apis": [
{
"path": "/apiKey"
},
{
"path": "/apiUser"
},
{
"path": "/attachment"
},
{
"path": "/layout"
},
{
"path": "/letter"
},
{
"path": "/ownedApiFile"
},
{
"path": "/person"
},
{
"path": "/post"
},
{
"path": "/register"
},
{
"path": "/signature"
},
{
"path": "/template"
},
{
"path": "/templateCategory"
}
],
"apiVersion": "0.1",
"swaggerVersion": "1.1"
}

why is that?

johnraz commented 10 years ago

This is "normal", do you have by any chance APPEND_SLASH=False in your settings ?

edit: and as for the way those urls are built, we are using tastypie's own internal methods.

dcale commented 10 years ago

Append slash is not set at all, but even if I set it to true it does not change anything...

I'll just adapt the tastypie_swagger urls for now, but it would be better if it would work "out of the box".

johnraz commented 10 years ago

It is working out of the box. I never had to mess with those urls to make it work, there is probably something in your specific setup that makes it fail. And actually I would like to fix it.

Could you provide a demo project that helps me reproduce this? Thanks

dcale commented 10 years ago

Don't get me wrong my comment "it would be better if it would out of the box", was not intended to be offensive, but rather on my own project specific. I'm fully aware that it's an issue with my own setup.

I'll prepare and send you the demo code shortly, thanks a lot for your help!

johnraz commented 10 years ago

Sweet! no offense taken ;-)

dcale commented 10 years ago

Ok, now I see the issue... I was preparing the demo code, and it turns out that

...
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

is screwing up the urls, this line was just used as hack by me in order to display uploaded images even when using the runserver command. This can be neglected, since if you deploy "normally" and don't serve static media through django and everything works as expected.

The bug can be closed.

johnraz commented 10 years ago

Ok, something like that is always nasty to diagnose... Closing ;-)