Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

coreapi only lists list and read method, even when user is logged

I'm building a Django Rest Framework and want to test the API with coreapi library. I can create an object using coreapi programmatically inside a python script but in command line, I can't create the same object and when I list coreapi endpoints I get a list with only endpoints for reading and listing, even when I add a valid credential.

My Schema:

{
    "_type": "document",
    "_meta": {
        "url": "http://127.0.0.1:8000/api/schema/",
        "title": "NEP API"
    },
    "experiments": {

        "list": {
            "_type": "link",
            "url": "/api/experiments/",
            "action": "get",
            "fields": [
                {
                    "name": "page",
                    "location": "query",
                    "schema": {
                        "_type": "integer",
                        "title": "Page",
                        "description": "A page number within the paginated result set."
                    }
                }
            ]
        },
        "create": {
            "_type": "link",
            "url": "/api/experiments/",
            "action": "post",
            "encoding": "application/json",
            "fields": [
                {
                    "name": "title",
                    "required": true,
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Title",
                        "description": ""
                    }
                },
                {
                    "name": "description",
                    "required": true,
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Description",
                        "description": ""
                    }
                },
                {
                    "name": "data_acquisition_done",
                    "location": "form",
                    "schema": {
                        "_type": "boolean",
                        "title": "Data acquisition done",
                        "description": ""
                    }
                },
                {
                    "name": "nes_id",
                    "required": true,
                    "location": "form",
                    "schema": {
                        "_type": "integer",
                        "title": "Nes id",
                        "description": ""
                    }
                },
                {
                    "name": "ethics_committee_file",
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Project file approved by the ethics committee",
                        "description": ""
                    }
                },
                {
                    "name": "sent_date",
                    "required": true,
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Sent date",
                        "description": ""
                    }
                }
            ]
        },
        "read": {
            "_type": "link",
            "url": "/api/experiments/{nes_id}/",
            "action": "get",
            "fields": [
                {
                    "name": "nes_id",
                    "required": true,
                    "location": "path",
                    "schema": {
                        "_type": "string",
                        "title": "",
                        "description": ""
                    }
                }
            ]
        },
        "update": {
            "_type": "link",
            "url": "/api/experiments/{nes_id}/",
            "action": "put",
            "encoding": "application/json",
            "fields": [
                {
                    "name": "nes_id",
                    "required": true,
                    "location": "path",
                    "schema": {
                        "_type": "string",
                        "title": "",
                        "description": ""
                    }
                },
                {
                    "name": "title",
                    "required": true,
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Title",
                        "description": ""
                    }
                },
                {
                    "name": "description",
                    "required": true,
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Description",
                        "description": ""
                    }
                },
                {
                    "name": "data_acquisition_done",
                    "location": "form",
                    "schema": {
                        "_type": "boolean",
                        "title": "Data acquisition done",
                        "description": ""
                    }
                },
                {
                    "name": "nes_id",
                    "required": true,
                    "location": "form",
                    "schema": {
                        "_type": "integer",
                        "title": "Nes id",
                        "description": ""
                    }
                },
                {
                    "name": "ethics_committee_file",
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Project file approved by the ethics committee",
                        "description": ""
                    }
                },
                {
                    "name": "sent_date",
                    "required": true,
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Sent date",
                        "description": ""
                    }
                }
            ]
        },
        "partial_update": {
            "_type": "link",
            "url": "/api/experiments/{nes_id}/",
            "action": "patch",
            "encoding": "application/json",
            "fields": [
                {
                    "name": "nes_id",
                    "required": true,
                    "location": "path",
                    "schema": {
                        "_type": "string",
                        "title": "",
                        "description": ""
                    }
                },
                {
                    "name": "title",
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Title",
                        "description": ""
                    }
                },
                {
                    "name": "description",
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Description",
                        "description": ""
                    }
                },
                {
                    "name": "data_acquisition_done",
                    "location": "form",
                    "schema": {
                        "_type": "boolean",
                        "title": "Data acquisition done",
                        "description": ""
                    }
                },
                {
                    "name": "nes_id",
                    "location": "form",
                    "schema": {
                        "_type": "integer",
                        "title": "Nes id",
                        "description": ""
                    }
                },
                {
                    "name": "ethics_committee_file",
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Project file approved by the ethics committee",
                        "description": ""
                    }
                },
                {
                    "name": "sent_date",
                    "location": "form",
                    "schema": {
                        "_type": "string",
                        "title": "Sent date",
                        "description": ""
                    }
                }
            ]
        },
        "delete": {
            "_type": "link",
            "url": "/api/experiments/{nes_id}/",
            "action": "delete",
            "fields": [
                {
                    "name": "nes_id",
                    "required": true,
                    "location": "path",
                    "schema": {
                        "_type": "string",
                        "title": "",
                        "description": ""
                    }
                }
            ]
        }
    },
}

As you see, all methods are listed here and I cant create an experiment object by using coreapi programmatically inside a script, for example, running (inside a python script):

client.action(
        schema, ['experiments', 'create'],
        params={'title': 'An experimet', 'description': 'A description',
                'nes_id': 2, 'sent_date': '2017-01-01'}
    )

But when using coreapi in command line I can't create same object.

Getting schema:

$ coreapi get http://127.0.0.1:8000/api/schema

display the and points when not logged:

<NEP API "http://127.0.0.1:8000/api/schema/">
    experiments: {
        groups: {
            list(experiment_nes_id, [page])
        }
        studies: {
            list(experiment_nes_id, [page])
        }
        list([page])
        read(nes_id)
    }
    groups: {
        list([page])
    }
    protocol_components: {
        list([page])
        read(nes_id)
    }
    studies: {
        list([page])
    }

Then, I add my credentials:

$ coreapi credentials add 127.0.0.1 "lab1":"nep-lab1" --auth basic

Reload the schema:

$ coreapi reload

and the result is again

<NEP API "http://127.0.0.1:8000/api/schema/">
    experiments: {
        groups: {
            list(experiment_nes_id, [page])
        }
        studies: {
            list(experiment_nes_id, [page])
        }
        list([page])
        read(nes_id)
    }
    groups: {
        list([page])
    }
    protocol_components: {
        list([page])
        read(nes_id)
    }
    studies: {
        list([page])
    }

Now, I expect that the endpoints would appear including create, update etc. but no.

And when I try to create an experiment object running:

$ coreapi action experiments create --param nes_id=5 --param title="A" --param description="B" --param sent_date="2001-01-01"

I get, as expected:

Index ['experiments']['create'] did not reference a link. Key 'create' was not found.

url conf:

I am using Default Router to generate REST uri's:

router.register(r'experiments', api.ExperimentViewSet,
                base_name='api_experiments')
router = DefaultRouter()

and including in url conf:

url(r'^', include(router.urls)),

Sorry by the long text. I wanted to include as much as information I thought was necessary.

like image 410
Caco Avatar asked May 26 '17 12:05

Caco


3 Answers

I found the exact same issue on Django Rest Framework tutorial, so it is still an issue with these versions:

$ pip list
...
coreapi (2.3.3)
coreapi-cli (1.0.6)
...

The issue documented here: https://github.com/core-api/coreapi-cli/issues/19. Relevant excerpt:

coreapi-cli is using the deprecated credentials argument for HTTPTransport instead of auth. As you can see from the code here, coreapi 2.3.1 is ingesting that deprecated argument, but then doing nothing with it. This is why this library won't send auth headers anymore.

I can confirm that adding the header fixed it for me. In summary:

coreapi clear
coreapi credentials add 127.0.0.1 admin:password --auth basic
coreapi credentials show
coreapi headers add "Authorization" "Basic ...=="
coreapi get http://127.0.0.1:8000/schema/ --debug

Copy-paste the string from "credentials show" command into "headers add" command.

like image 159
Oikos Avatar answered Oct 21 '22 00:10

Oikos


Had the same issue when working on tutorial (part 7) at official Django Rest Framework site.

Found one solution: manually add header Authorization to requests using coreapi headers add HEADER VALUE, where VALUE is the string of characters, which is generated when you add credentials of user. For some reason my coreapi didn't add this header automatically to request as I found with --debug option.

Here is example:

Before credentials are added I can see only safe methods:

$ coreapi get http://127.0.0.1:8000/schema/
<Pastebin API "http://127.0.0.1:8000/schema/">
    snippets: {
        list([page])
        read(id)
        highlight(id)
    }
    users: {
        list([page])
        read(id)
    }

Then I add credentials of superuser admin:

coreapi credentials add 127.0.0.1 "admin:password" --auth basic
Added credentials
127.0.0.1 "Basic BlahBlahBlah="

It looks like coreapi successfully add credentials, but when I try to reload schema, I still get the same methods:

$ coreapi reload
<Pastebin API "http://127.0.0.1:8000/schema/">
    snippets: {
        list([page])
        read(id)
        highlight(id)
    }
    users: {
        list([page])
        read(id)
    }

I found that there is no Authorization header in GET request with value Basic BlahBlahBlah=:

$ coreapi reload --debug
> GET /schema/ HTTP/1.1
> Accept-Encoding: gzip, deflate
> Connection: keep-alive
> Accept: application/coreapi+json, application/vnd.coreapi+json, */*
> Host: 127.0.0.1
> User-Agent: coreapi

Well, let's try to add this header to our request manually:

$ coreapi headers add "Authorization" "Basic BlahBlahBlah="
Added header
Authorization: Basic BlahBlahBlah=

Try again to get schema:

$ coreapi get http://127.0.0.1:8000/schema/
<Pastebin API "http://127.0.0.1:8000/schema/">
    snippets: {
        list([page])
        create(code, [title], [linenos], [language], [style])
        read(id)
        update(id, code, [title], [linenos], [language], [style])
        partial_update(id, [title], [code], [linenos], [language], [style])
        delete(id)
        highlight(id)
    }
    users: {
        list([page])
        read(id)
    }

Now I see all other methods available to authorized users only. If I execute previous command with --debug option, there will be the header:

> GET /schema/ HTTP/1.1
> Accept-Encoding: gzip, deflate
> Connection: keep-alive
> Accept: application/coreapi+json, application/vnd.coreapi+json, */*
> Authorization: Basic BlahBlahBlah=
> Host: 127.0.0.1
> User-Agent: coreapi

For example, now I can create code snippet:

$ coreapi action snippets create --param title="Example" --param code="print('hello, world')"
{
    "url": "http://127.0.0.1:8000/snippets/6/",
    "id": 6,
    "highlight": "http://127.0.0.1:8000/snippets/6/highlight/",
    "owner": "admin",
    "title": "Example",
    "code": "print('hello, world')",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}

But still there is the question Why doesn't coreapi add Authorization header automatically?

like image 23
Sergey Dulevich Avatar answered Oct 21 '22 00:10

Sergey Dulevich


This is a known bug with version 2.3.x. of coreapi-cli. A fix is coming soon, see:

Issue tracked on Github

The work around is as per Sergey Dulevich's previous answer.

like image 26
AmateurAardvark Avatar answered Oct 20 '22 23:10

AmateurAardvark