Project

General

Profile

Task #1900

API: Adding attributes in JSON Response

Added by Kurt Gerber almost 5 years ago. Updated over 4 years ago.

Status:
In Progress
Priority:
High
Category:
Dev Task
Start date:
17 Dec 2019
Due date:
% Done:

0%

Estimated time:
Resolution:
fixed

Description

The API endpoint

.../api/v2/questionnaires/

responds with a list of cases (technologies/approaches).

for each case it lists the following attributes:

"results": [
        {
            "name": "Community-based Natural Resource Management",
            "updated": "2017-08-23T15:00:47.172403+02:00",
            "code": "approaches_2542",
            "edition": "2015",
            "url": "/en/wocat/approaches/view/approaches_2542/",
            "translations": [
                [
                    "en",
                    "English" 
                ]
            ],
            "details": "/en/api/v2/questionnaires/approaches_2542/" 
        },
   ...
Different metadata attributes should be added to this output, which are not available in the detail neither:
  • created : <TIMESTAMP> - timestamp, on which the case was created/added
  • compiler: <Name> - The compiler, e.g. author, of the case
  • reviewer: [<Name>,<Name>,...] - list of reviewers of this case

All those attributes are visible in the web interface on the detail page of a technology or approach. But all those informations are missing in the API.

So the JSON response should look like (example from above):

"results": [
        {
            "name": "Community-based Natural Resource Management",
            "created":"2016-09-02 23:59:59+02:00",
            "updated": "2017-08-23T15:00:47.172403+02:00",
             "compiler":"Aqila Haidery" 
             "reviewer":["Deborah Niggli"]
            "code": "approaches_2542",
            "edition": "2015",
            "url": "/en/wocat/approaches/view/approaches_2542/",
            "translations": [
                [
                    "en",
                    "English" 
                ]
            ],
            "details": "/en/api/v2/questionnaires/approaches_2542/" 
        },
   ...

Files

tests_log_09Apr20.log (102 KB) tests_log_09Apr20.log Brahadeesh Dheenadayalan_Sivakami, 09 Apr 2020 21:52
#1

Updated by Kurt Gerber almost 5 years ago

  • Status changed from New to Accepted
#2

Updated by Brahadeesh Dheenadayalan_Sivakami almost 5 years ago

  • Status changed from Accepted to Feedback
  • Assignee changed from Brahadeesh Dheenadayalan_Sivakami to Kurt Gerber
  • Resolution set to fixed

Hi Kurt,
I have added the requested fields to the questionnaire API call.
If the pull request can be merged into develop branch it can be tested before it gets pushed to master.

Thanks,
Guhan

#3

Updated by Kurt Gerber almost 5 years ago

  • Status changed from Feedback to In Progress
  • Assignee changed from Kurt Gerber to Brahadeesh Dheenadayalan_Sivakami

After merging the respective pull request, the tests on CI instance are failing:

apps/questionnaire/tests/test_api.py is now failing,
I guess you have to adapt those tests.

Do you have access to shippable.com?
If you need to see more, you should run the tests on your own instance.

Here is the log of the three failed tests from shippable.com:

self = <apps.questionnaire.tests.test_api.QuestionnaireListViewTest testMethod=test_api_url_detail_v1>

    def test_api_url_detail_v1(self):
        items = [{'code': 'spam', 'configuration': 'sample'}]
>       updated = list(self.view.filter_dict(items))

apps/questionnaire/tests/test_api.py:147: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <questionnaire.api.views.QuestionnaireListView object at 0x7f5670dd95f8>
items = [{'code': 'spam', 'configuration': 'sample'}]

    def filter_dict(self, items: dict):
        """ 
            Starting with API v2 only name and url to the detail page are displayed.
            """ 
        for item in items:
            yield {
                'name': item.get('name'),
                'created': item.get('created'),
                'updated': item.get('updated'),
>               'compiler': item.get('compilers')[0]['name'],
                'reviewer': [reviewers['name'] for reviewers in item.get('reviewers')],
                'code': item.get('code'),
                'edition': item.get('serializer_edition'),
                'url': reverse(
                    viewname='{configuration}:questionnaire_details'.format(
                        configuration=item['configuration']
                    ),
                    kwargs={'identifier': item['code']}),
                'translations': item.get('translations'),
                'details': reverse(
                    '{api_version}:questionnaires-api-detail'.format(
                        api_version=self.request.version
                    ), kwargs={'identifier': item['code']}
                ),
            }
E           TypeError: 'NoneType' object is not subscriptable

apps/questionnaire/api/views.py:106: TypeError

pytest / apps.questionnaire.tests.test_api.QuestionnaireListViewTest / test_api_url_detail_v2

: TypeError: 'NoneType' object is not subscriptable

self = <apps.questionnaire.tests.test_api.QuestionnaireListViewTest testMethod=test_api_url_detail_v2>

    def test_api_url_detail_v2(self):
        items = [{'code': 'spam', 'configuration': 'sample'}]
        request = self.request
        request.version = 'v2'
        view = self.setup_view(self.view, request)
>       updated = list(view.filter_dict(items))

apps/questionnaire/tests/test_api.py:157: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <questionnaire.api.views.QuestionnaireListView object at 0x7f5670570160>
items = [{'code': 'spam', 'configuration': 'sample'}]

    def filter_dict(self, items: dict):
        """ 
            Starting with API v2 only name and url to the detail page are displayed.
            """ 
        for item in items:
            yield {
                'name': item.get('name'),
                'created': item.get('created'),
                'updated': item.get('updated'),
>               'compiler': item.get('compilers')[0]['name'],
                'reviewer': [reviewers['name'] for reviewers in item.get('reviewers')],
                'code': item.get('code'),
                'edition': item.get('serializer_edition'),
                'url': reverse(
                    viewname='{configuration}:questionnaire_details'.format(
                        configuration=item['configuration']
                    ),
                    kwargs={'identifier': item['code']}),
                'translations': item.get('translations'),
                'details': reverse(
                    '{api_version}:questionnaires-api-detail'.format(
                        api_version=self.request.version
                    ), kwargs={'identifier': item['code']}
                ),
            }
E           TypeError: 'NoneType' object is not subscriptable

apps/questionnaire/api/views.py:106: TypeError

pytest / apps.questionnaire.tests.test_api.QuestionnaireListViewTest / test_api_v2_language_aware

: TypeError: 'NoneType' object is not subscriptable

self = <apps.questionnaire.tests.test_api.QuestionnaireListViewTest testMethod=test_api_v2_language_aware>
mock_reverse = <MagicMock name='reverse' id='140009211050920'>

    @patch('questionnaire.api.views.reverse')
    def test_api_v2_language_aware(self, mock_reverse):
        items = [{'code': 'spam', 'configuration': 'sample'}]
        request = self.request
        request.version = 'v2'
        view = self.setup_view(self.view, request)
>       list(view.filter_dict(items))

apps/questionnaire/tests/test_api.py:168: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <questionnaire.api.views.QuestionnaireListView object at 0x7f56704c7358>
items = [{'code': 'spam', 'configuration': 'sample'}]

    def filter_dict(self, items: dict):
        """ 
            Starting with API v2 only name and url to the detail page are displayed.
            """ 
        for item in items:
            yield {
                'name': item.get('name'),
                'created': item.get('created'),
                'updated': item.get('updated'),
>               'compiler': item.get('compilers')[0]['name'],
                'reviewer': [reviewers['name'] for reviewers in item.get('reviewers')],
                'code': item.get('code'),
                'edition': item.get('serializer_edition'),
                'url': reverse(
                    viewname='{configuration}:questionnaire_details'.format(
                        configuration=item['configuration']
                    ),
                    kwargs={'identifier': item['code']}),
                'translations': item.get('translations'),
                'details': reverse(
                    '{api_version}:questionnaires-api-detail'.format(
                        api_version=self.request.version
                    ), kwargs={'identifier': item['code']}
                ),
            }
E           TypeError: 'NoneType' object is not subscriptable

apps/questionnaire/api/views.py:106: TypeError
#4

Updated by Brahadeesh Dheenadayalan_Sivakami almost 5 years ago

  • Assignee changed from Brahadeesh Dheenadayalan_Sivakami to Kurt Gerber

Hi Kurt,
I think I have a solution for the issue but when running the test locally, I keep getting the following error
(I also tried with a version before I added the additional attributes but got the same error.)

ERROR: test_api_url_detail_v1 (apps.questionnaire.tests.test_api.QuestionnaireListViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/code/apps/questionnaire/tests/test_api.py", line 30, in setUp
create_temp_indices([('sample', '2015')])
File "/code/apps/search/tests/test_index.py", line 54, in create_temp_indices
Questionnaire.with_status.public().filter(configuration__code=code)
File "/code/apps/search/index.py", line 305, in put_questionnaire_data
serialized = QuestionnaireSerializer(instance=obj).data
File "/usr/local/lib/python3.6/site-packages/rest_framework/serializers.py", line 560, in data
ret = super(Serializer, self).data
File "/usr/local/lib/python3.6/site-packages/rest_framework/serializers.py", line 262, in data
self._data = self.to_representation(self.instance)
File "/usr/local/lib/python3.6/site-packages/rest_framework/serializers.py", line 527, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/usr/local/lib/python3.6/site-packages/rest_framework/fields.py", line 1855, in to_representation
return method(value)
File "/code/apps/questionnaire/serializers.py", line 89, in get_url
return url[url.find('/', 1):]
AttributeError: 'NoneType' object has no attribute 'find'

Any ideas on how to workaround this would help greatly. I am attempting to configure shippable for my fork but it might take me a while.
In the meanwhile I will go ahead and post my update as a new pull request.
Maybe Lukas or Sebastian will have some feedback as well?

Thanks,
Guhan

#5

Updated by Kurt Gerber almost 5 years ago

The tests are still failing. Also on shippable. If you are running the tests on your own, you don't need to set up shippable for your fork.
As you say; tests fail also consistently to shippable when run on your own instance.

I can't help concerning the code. Maybe you should get in touch with Kevin?

Regards,
Kurt

#6

Updated by Kurt Gerber almost 5 years ago

  • Assignee changed from Kurt Gerber to Brahadeesh Dheenadayalan_Sivakami
#7

Updated by Kurt Gerber almost 5 years ago

Any news on this? I did a git revert to remove tha merged commits concerning this pull request. So that CI is again deploying successully.

#8

Updated by Brahadeesh Dheenadayalan_Sivakami over 4 years ago

Hi Kurt,
Sorry for the delay in getting back to you on this.
After spending much time, here is what I have discovered.
The tests run on shippable are different from the tests I am running on local.

shippable uses pytest whereas I am using manage.py test which is working differently. I have included the log of the errors from running manage.py test apps on develop.

Is there some qcat documentation that Sebastian and/or Lukas put together on how the pytest is configured and how I can run on my local machine?
This would be of great help. I have been going around in circles and it has left me a little frustrated.

The code changes implemented obviously work, the API endpoint returns the created, compiler and reviewer attributes on testing using Postman.

Thanks,
Guhan

#9

Updated by Brahadeesh Dheenadayalan_Sivakami over 4 years ago

  • Assignee changed from Brahadeesh Dheenadayalan_Sivakami to Kurt Gerber
#10

Updated by Kurt Gerber over 4 years ago

  • Assignee changed from Kurt Gerber to Brahadeesh Dheenadayalan_Sivakami

Guhan, I'm sorry but I can't help here and all available is on documentation is on qcat.readthedocs.io. There is no further documentation.
I don't know, why they use pytest on shippable. I do not know about the differences. But as far as I can see, it tests the same.
Are there still tests failing on shippable but not failing on your side?

There is a lot on the web about pytest vs. Django testing and how to use both. It is up to you to harmonize that in the way that you use also pytest on your local machine.

I'm sorry not to be able to help more. But that is exactly the point: I can't ask Sebastian and Lukas anymore and myself I'm not that familiar with the code, especially with testing.

Also available in: Atom PDF