Flasgger - Add bearer authorization - python

I am running a flask app and using flasgger to generate Swagger Specs as well as a Swagger UI. My API requires the requests to be authenticated using a bearer token. I am able to get the button on the page and set the token. But it is not sent through the requests. I am using OpenAPI 3.0.3. Below is my code:
from flasgger import Swagger
swagger_template = {
'components': {
'securitySchemes': {
'bearerAuth': {
'type': 'http',
'scheme': 'bearer',
'bearerFormat': 'JWT'
}
},
'security': {
'bearerAuth': []
}
}
}
# Register controllers
api = Api(app)
swagger = Swagger(app=app, config={
'headers': [
],
'title': 'Model Design Application API',
'specs': [
{
'endpoint': 'apispec',
'route': '/apispec.json'
}
],
'openapi': '3.0.3'
}, template=swagger_template)
This is the token to be set in the Swagger UI:
This is the UI I get in Swagger:
This is the apispec.json that is generated:
{
"definitions": {
"User": {
"properties": {
"username": {
"default": "Steven Wilson",
"description": "The name of the user",
"type": "string"
}
}
}
},
"info": {
"description": "powered by Flasgger",
"termsOfService": "/tos",
"title": "Model Design Application API",
"version": "0.0.1"
},
"openapi": "3.0.3",
"paths": {
"/profile": {
"get": {
"description": "It works also with swag_from, schemas and spec_dict<br/>",
"responses": {
"200": {
"description": "A single user item",
"schema": {
"$ref": "#/definitions/User"
}
}
},
"summary": "This examples uses FlaskRESTful Resource"
}
}
},
"security": {
"bearerAuth": []
},
"securitySchemes": {
"bearerAuth": {
"bearerFormat": "JWT",
"scheme": "bearer",
"type": "http"
}
}
}
Please advice. Any help is appreciated.

For adding header in Flasgger API, do the following changes:
SWAGGER_TEMPLATE = {"securityDefinitions": {"APIKeyHeader": {"type": "apiKey", "name": "x-access-token", "in": "header"}}}
swagger = Swagger(app, template=SWAGGER_TEMPLATE)
Here, x-access-token is our key name in header. you can change this name according to your requirement.
After this, we need to add this header in our .yml file. Our .yml file will look like this:
summary: "Put your summery here."
description: "Put your description here."
consumes:
- "application/json"
produces:
- "application/json"
security:
- APIKeyHeader: ['x-access-token']
responses:
200:
description: "Success"

Check the working code here
template = {
"swagger": "2.0",
"info": {
"title": XYZ API Docs",
"description": "API Documentation for XYZ Application",
"contact": {
"responsibleOrganization": "",
"responsibleDeveloper": "",
"email": "XYZ#XYZ.com",
"url": "XYZ.com",
},
"termsOfService": "XYZ .com",
"version": "1.0"
},
"basePath": "/api/v1", # base bash for blueprint registration
"schemes": [
"http",
"https"
],
"securityDefinitions": {
"Bearer": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
"description": "\
JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\""
}
},
"security": [
{
"Bearer": []
}
]
}
swagger_config = {
"headers": [
],
"specs": [
{
"endpoint": 'apispec',
"route": '/apispec.json',
"rule_filter": lambda rule: True, # all in
"model_filter": lambda tag: True, # all in
}
],
"static_url_path": "/flasgger_static",
"swagger_ui": True,
"specs_route": "/api/v1/apispec"
}

Related

How to use Here Api to get Max speed limit of road using latitude and longitude in python environment

We are new to Here Api,
Our team is working on one transportation project in which we required to get max speed limit of road using vehicle (latitude ,longitude).
From last few days we are trying to figure out which api should we use in HereApi to achieve what we want.
Regarding this documentation of HERE Route Matching 8: https://developer.here.com/documentation/route-matching/api-reference.html
Send please POST request like:
https://routematching.hereapi.com/v8/match/routelinks?apikey=LXX1Axs75efnlFAlgbPxVekPDR0Hz6rTcRHQMT0EvQs&routeMatch=1&mode=fastest;car;traffic:disabled;&attributes=SPEED_LIMITS_FCn(*),LINK_ATTRIBUTE_FCn(*),TRAFFIC_PATTERN_FCn(*),TRUCK_SPEED_LIMITS_FCn(*),SPEED_LIMITS_VAR_FCn(*),SPEED_LIMITS_COND_FCn(*)
With in body:
LATITUDE,LONGITUDE
37.4201866,15.049515
See please attached the Postman collection for test of HERE Rote Match API v8 https://developer.here.com/documentation/route-matching/dev_guide/index.html :
{
"info": {
"_postman_id": "2563b7cc-2d62-4485-bb64-2f9561318aa2",
"name": "RMEspeed_limit",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "1051680"
},
"item": [
{
"name": "speed_limit",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "LATITUDE,LONGITUDE\r\n37.4201866,15.049515"
},
"url": {
"raw": "https://routematching.hereapi.com/v8/match/routelinks?apikey=LXX1Axs75efnlFAlgbPxVekPDR0Hz6rTcRHQMT0EvQs&routeMatch=1&mode=fastest;car;traffic:disabled;&attributes=SPEED_LIMITS_FCn(*),LINK_ATTRIBUTE_FCn(*),TRAFFIC_PATTERN_FCn(*),TRUCK_SPEED_LIMITS_FCn(*),SPEED_LIMITS_VAR_FCn(*),SPEED_LIMITS_COND_FCn(*) ",
"protocol": "https",
"host": [
"routematching",
"hereapi",
"com"
],
"path": [
"v8",
"match",
"routelinks"
],
"query": [
{
"key": "apikey",
"value": "LXX1Axs75efnlFAlgbPxVekPDR0Hz6rTcRHQMT0EvQs"
},
{
"key": "routeMatch",
"value": "1"
},
{
"key": "mode",
"value": "fastest;car;traffic:disabled;"
},
{
"key": "attributes",
"value": "SPEED_LIMITS_FCn(*),LINK_ATTRIBUTE_FCn(*),TRAFFIC_PATTERN_FCn(*),TRUCK_SPEED_LIMITS_FCn(*),SPEED_LIMITS_VAR_FCn(*),SPEED_LIMITS_COND_FCn(*) "
}
]
}
},
"response": []
}
]
}
An apikey and coordinate you specify your own for sure.
About all layers attributes you can see this example: https://demo.support.here.com/pde/maps?url_root=pde.api.here.com
In Python you should use normal POST request using some http libraries developed for Python:
https://www.geeksforgeeks.org/get-post-requests-using-python/

How do i disable Facebook messenger persistent menu?

I recently enabled persistent_menu for my bot but now I want to disable it.
Below is how i enabled it
data={
"psid" : uid,
"persistent_menu" : [{
"locale" : "default",
"composer_input_disabled" : False,
"call_to_actions" : [
{
"type": "postback",
"title": "Request Ride",
"payload": "Request Ride"
},
{
"type": "postback",
"title": "Call Customer Service",
"payload": "Call"
},
]
}]
}
r = requests.post("https://graph.facebook.com/v6.0/me/custom_user_settings?access_token=<PAGE TOKEN>", data=json.dumps(data), headers={"Content-Type" : "application/json"})
To disable it, simply omit the call_to_actions field:
{
"psid": <PSID>,
"persistent_menu": [
{
"locale": "default",
"composer_input_disabled": false
}
]
}

API.ai Actions on Google API Version 2: Failed to parse JSON response string with 'INVALID_ARGUMENT' error: ": Cannot find field."

I am using python to create webhook for Assistat app. I am able to ask user for location permission, but as soon as user gives consent, I receive following error
UnparseableJsonResponse
API Version 2: Failed to parse JSON response string with 'INVALID_ARGUMENT' error: ": Cannot find field.".
I have checked my webhook server and no request comes to it. This looks like some issue at API.ai side. Below is the Debug response from Actions console when using Python client
{
"assistantToAgentDebug": {
"curlCommand": "curl -v '<URL>'{\"user\":{\"userId\":\"<USED_ID>\",\"locale\":\"en-US\"},\"conversation\":{\"conversationId\":\"1504592665563\",\"type\":\"ACTIVE\",\"conversationToken\":\"[\\\"defaultwelcomeintent-followup\\\"]\"},\"inputs\":[{\"intent\":\"actions.intent.PERMISSION\",\"rawInputs\":[{\"inputType\":\"VOICE\",\"query\":\"yes\"}],\"arguments\":[{\"name\":\"PERMISSION\",\"textValue\":\"true\"}]}],\"surface\":{\"capabilities\":[{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"}]},\"device\":{\"location\":{\"coordinates\":{\"latitude\":37.4219806,\"longitude\":-122.0841979}}},\"isInSandbox\":true}'",
"assistantToAgentJson": {
"user": {
"userId": "<USED_ID>",
"locale": "en-US"
},
"conversation": {
"conversationId": "1504592665563",
"type": "ACTIVE",
"conversationToken": "[\"defaultwelcomeintent-followup\"]"
},
"inputs": [
{
"intent": "actions.intent.PERMISSION",
"rawInputs": [
{
"inputType": "VOICE",
"query": "yes"
}
],
"arguments": [
{
"name": "PERMISSION",
"textValue": "true"
}
]
}
],
"surface": {
"capabilities": [
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
}
]
},
"device": {
"location": {
"coordinates": {
"latitude": 37.4219806,
"longitude": -122.0841979
}
}
},
"isInSandbox": true
}
},
"agentToAssistantDebug": {
"agentToAssistantJson": {
"message": "Unexpected apiai response format: Empty speech response",
"apiResponse": {
"id": "<ID>",
"timestamp": "2017-09-05T06:24:41.711Z",
"lang": "en",
"result": {},
"status": {
"code": 200,
"errorType": "success"
},
"sessionId": "1504592665563"
}
}
},
"sharedDebugInfo": [
{
"name": "GOOGLE_SYSTEM_ACTION",
"debugInfo": "Your query was handled by Actions on Google."
},
{
"name": "GOOGLE_SYSTEM_ACTION",
"debugInfo": "Your query was handled by Actions on Google."
},
{
"name": "ResponseValidation",
"subDebugEntry": [
{
"name": "UnparseableJsonResponse",
"debugInfo": "API Version 2: Failed to parse JSON response string with 'INVALID_ARGUMENT' error: \": Cannot find field.\"."
}
]
}
]
}
Using Python library Flask-Assistant
How can I resolve this issue?
UPDATE
Node JS client works... what is the issue with Python client?
Action Console Debug response
{
"assistantToAgentDebug": {
"curlCommand": "curl -v '<URL>'{\"user\":{\"userId\":\"<USER_ID>\",\"locale\":\"en-US\"},\"conversation\":{\"conversationId\":\"<ID>\",\"type\":\"ACTIVE\",\"conversationToken\":\"[\\\"_actions_on_google_\\\",\\\"defaultwelcomeintent-followup\\\"]\"},\"inputs\":[{\"intent\":\"actions.intent.PERMISSION\",\"rawInputs\":[{\"inputType\":\"VOICE\",\"query\":\"yes\"}],\"arguments\":[{\"name\":\"PERMISSION\",\"textValue\":\"true\"}]}],\"surface\":{\"capabilities\":[{\"name\":\"actions.capability.AUDIO_OUTPUT\"}]},\"device\":{\"location\":{\"coordinates\":{\"latitude\":37.4219806,\"longitude\":-122.0841979},\"formattedAddress\":\"Googleplex, Mountain View, CA 94043, United States\",\"zipCode\":\"94043\",\"city\":\"Mountain View\"}},\"isInSandbox\":true}'",
"assistantToAgentJson": {
"user": {
"userId": "<USER_ID>",
"locale": "en-US"
},
"conversation": {
"conversationId": "<ID>",
"type": "ACTIVE",
"conversationToken": "[\"_actions_on_google_\",\"defaultwelcomeintent-followup\"]"
},
"inputs": [
{
"intent": "actions.intent.PERMISSION",
"rawInputs": [
{
"inputType": "VOICE",
"query": "yes"
}
],
"arguments": [
{
"name": "PERMISSION",
"textValue": "true"
}
]
}
],
"surface": {
"capabilities": [
{
"name": "actions.capability.AUDIO_OUTPUT"
}
]
},
"device": {
"location": {
"coordinates": {
"latitude": 37.4219806,
"longitude": -122.0841979
},
"formattedAddress": "Googleplex, Mountain View, CA 94043, United States",
"zipCode": "94043",
"city": "Mountain View"
}
},
"isInSandbox": true
}
},
"agentToAssistantDebug": {
"agentToAssistantJson": {
"conversationToken": "[\"_actions_on_google_\",\"defaultwelcomeintent-followup\"]",
"expectUserResponse": true,
"expectedInputs": [
{
"inputPrompt": {
"richInitialPrompt": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Given permission"
}
}
]
}
},
"possibleIntents": [
{
"intent": "assistant.intent.action.TEXT"
}
]
}
],
"responseMetadata": {
"status": {
"code": 14
},
"queryMatchInfo": {
"queryMatched": true,
"intent": "Default Welcome Intent - fallback"
}
}
}
}
}
Request from Actions server to my Node JS webhook server
{ originalRequest:
{ source: 'google',
version: '2',
data:
{ isInSandbox: true,
surface: [Object],
inputs: [Array],
user: [Object],
device: [Object],
conversation: [Object] } },
id: '<ID>',
timestamp: '2017-09-06T05:43:21.342Z',
lang: 'en',
result:
{ source: 'agent',
resolvedQuery: 'actions_intent_PERMISSION',
speech: '',
action: 'DefaultWelcomeIntent.DefaultWelcomeIntent-fallback',
actionIncomplete: false,
parameters: {},
contexts: [ [Object], [Object], [Object], [Object], [Object] ],
metadata:
{ intentId: '<ID>',
webhookUsed: 'true',
webhookForSlotFillingUsed: 'false',
nluResponseTime: 2,
intentName: 'Default Welcome Intent - fallback' },
fulfillment: { speech: 'Given permission', messages: [Array] },
score: 1 },
status: { code: 200, errorType: 'success' },
sessionId: '<SID>'
}
API.ai Intent settings
The most likely reason you're not getting any hits on your webhook is that you don't have an intent registered to get the reply.
You can do this by creating an Intent with the Event set to actions_intent_PERMISSION.
See also the following answers on SO:
Unable to accept the permission prompt on Actions on Google
Permission response not handled correctly

How to connect one pano to multiple panos using Google street view publish API?

I'm using photo.update request for panos(360 panoramic images) connection in python. I'm able to do only connect one pano to another pano but I want to connect one pano to multiple panos. I'm not getting a successful result.
I have sent the following photoUpdate request using Python:
update_photo_url = 'https://streetviewpublish.googleapis.com/v1/photo/{}?key={}&updateMask=connections'.format("pano_1","AIzdesdfyxscvvvvvvvvvvvvvvv")
headers = {"Authorization": "Bearer {}".format("ya29.Glx6BO91jWbjzLQKYPvP16fhT-jyOEnIdnoRcZcU9uYCqzwH3Dkuf-qf_kzUc2ykYOyVTZCfaGjOEAScsJK7WgS4NE9gfS6bSobWDIMdfpfY7SPzRMmxi4kfTrmsRQ"), "Content-Length": "0", "Content-Type": "application/json"}
update_body = {
[
{
"photo": {
"photoId": {
"id": "pano_1"
},
"connections": {
"target": {
"id": "pano_2"
},
"target": {
"id": "pano_3"
}
},
}
}
]
}
update_response = requests.put(update_photo_url,headers=headers,json=update_body)
update_response.text
Error:
{
"error": {
"code": 400,
"message": "Invalid JSON payload received. Unknown name \"\": Root element must be a message.",
"status": "INVALID_ARGUMENT",
"details": [
{
"#type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"description": "Invalid JSON payload received. Unknown name \"\": Root element must be a message."
}
]
}
]
}
}
Anyone know about, How to connect multiple 360 panos from the source pano? It would be really great if someone could clarify on the possibility of it.Thanks in advance.
I've seen that your request URL is:
https://streetviewpublish.googleapis.com/v1/photo/{}?key={}&updateMask=connections'.format("pano_1","AIzdesdfyxscvvvvvvvvvvvvvvv")
In order to connect multiple photos, you need to use the batchUpdate method.
HTTP request
POST https://streetviewpublish.googleapis.com/v1/photos:batchUpdate?
Here's a sample request using curl:
curl --request POST \
--url 'https://streetviewpublish.googleapis.com/v1/photos:batchUpdate' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"updatePhotoRequests": [
{
"updateMask": "connections",
"photo": {
"photoId": {
"id": "pano_1"
},
"connections": [
{
"target": {
"id": "pano_2"
}
},
{
"target": {
"id": "pano_3"
}
}
]
}
}
]
}'
Update: If I have four panos and I want to connect pano_1 -> pano_2, pano_3 and pano_3 -> pano_4 then what will be the json format?
You should make pano_4 as your target to be connected to pano_3.
{
"updatePhotoRequests": [
{
"updateMask": "connections",
"photo": {
"photoId": {
"id": "pano_3"
},
"connections": [
{
"target": {
"id": "pano_4"
}
},
]
}
}
]
}
Just be noted that the id should be photoId of the uploaded photo.

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.
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?
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.
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.
Just wanted to mention that i do not see these issue's when using the python client directly (when providing Basic Auth credentials).
from coreapi import Client
client = Client(auth=HTTPBasicAuth('user', 'pass'))
document = client.get(args.endpoint)
data = client.action(document, ['catalog', 'create', ], params={
'start': '2018-08-30T10:00:00Z',
'end': '2018-08-30T11:00:00Z',
'filename': 'my-filename',
})
This also happened to me after authenticating on basic-auth with:
$ coreapi credentials add 127.0.0.1 <user>:'<pass>' --auth basic
Now you will find the REST un-SAFE methods are listed, using: coreapi action snippets list - check for those methods:
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)
read_0(id, format)
read_1(id, format)
update_0(id, format, code, [title], [linenos], [language], [style])
partial_update_0(id, format, [title], [code], [linenos], [language], [style])
delete_0(id, format)
Then if I tried to create a resource such as:
$ coreapi action snippets create --param title="Example" --param code="print('hello, world from the CLI')"
it would fail with "Index ['snippets']['create'] did not reference a link. Key 'create' was not found."
I was able to solve it by reading again the schema after the auth step:
$ coreapi get http://127.0.0.1:8008/schema/
This must act like a refresh of the schema and it then allows to create the resource using the exact same code from above.
Try it and see if it works for you as well.

Categories