OpenAPI v3 / Swagger - calling a function and sending json dictionary to it - swagger

I'm trying to use OpenAPI/Swagger to run an endpoint capable of consuming a json dictionary, sending to a function and getting a response.
I'm using operationId to refer to the function that I want to call, but can't work out how to send the dictionary that's received by the endpoint.
controllers.get_options is called, but no parameters are sent to it with my current approach.
I think I'm missing something obvious, but it's not apparent!
I would call the endpoint like this:
curl -X 'POST' \
'http://localhost:8080/getoptions' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"product_area": "Main",
"product_type": "New"
}'
This is the openapi config file (./openapi.yaml)
EDIT: adding x-body-name: DiscussionResult below solved the issue as per Helen's comment
openapi: 3.0.0
info:
title: Test
version: '1.0'
paths:
/getoptions:
post:
description: Return product options from product type and area
operationId: controllers.get_options
requestBody:
required: true
content:
application/json:
x-body-name: DiscussionResult
schema:
$ref: '#/components/schemas/DiscussionResult'
responses:
200:
description: "success"
components:
schemas:
DiscussionResult:
type: object
discriminator:
propertyName: product_type
properties:
product_type:
type: string
example: "New"
product_area:
type: string
example: "Main"
I'm running it using connexion as shown here:
main.py
import connexion
import logging
def create_app():
logging.basicConfig(level=logging.DEBUG)
connex_app = connexion.FlaskApp(__name__, specification_dir="./openapi/")
connex_app.add_api("./openapi.yaml", resolver_error=501)
return connex_app
if __name__ == "__main__":
app = create_app()
app.run(host="0.0.0.0", port=8080)
requirements.txt
connexion[swagger-ui]
connexion>=2.2.0
python-jose[cryptography]
six>=1.9
Flask>=0.10.1
sqlathanor
and this is the function that I want to call
def get_options(DiscussionResult):
msg = "{} {}".format(DiscussionResult['product_area'], DiscussionResult['product_type'])
return jsonify(message=msg), 200

Connexion docs on Request Handling include the following note:
In the OpenAPI 3.x.x spec, the requestBody does not have a name. By default it will be passed in as ‘body’. You can optionally provide the x-body-name parameter in your requestBody schema to override the name of the parameter that will be passed to your handler function.
Looks like you need to add x-body-name: DiscussionResult to the DiscussionResult schema that is used in the requestBody:
components:
schemas:
DiscussionResult:
x-body-name: DiscussionResult # <---------
type: object
...
or
requestBody:
required: true
content:
application/json:
schema:
x-body-name: DiscussionResult # <---------
$ref: '#/components/schemas/DiscussionResult'

I'd very much recommend FastApi as I already said in the comments earlier. Here is a little bit of a working code.
main.py
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class DetailsModel(BaseModel):
product_area: str
product_type: str
#app.post("/get_details")
async def _(
input_json: DetailsModel
):
return {"returns": input_json.dict()}
Run uvicorn main:app --reload from root directory
Then check http://127.0.0.1:8000/docs
Then you can call:
curl -X 'POST' \
'http://127.0.0.1:8000/get_details' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"product_area": "Main",
"product_type": "New"
}'
Fastapi checks for any unprocessable entities with Pydantic which helps a lot with any requests that doesn't fit the model.
Check the official and very detailed documentation too https://fastapi.tiangolo.com/.

Related

How to use simple hello world example on opa server

I have defined a file with name - play.rego
package play
default hello = false
hello {
m := input.message
m == "world"
}
I also have file called -input.json
{ "message": "world"}
I now want to use the policy to evaluate on input data using opa server -
opa run --server
I also then registered the policy using below command -
curl -X PUT http://localhost:8181/v1/policies/play --data-binary #play.rego
and then I run below command for evaluating policy on the query -
curl -X POST http://localhost:8181/v1/policies/v1/data/play --data-binary '{"message": "world"}'
But the server always responds with nothing.
I need help fixing the problem?
The URL of the second request is wrong (should not contain v1/policies), and the v1 API requires you to wrap the input document inside an input attribute. Try:
curl -X POST http://localhost:8181/v1/data/play --data-binary '{"input":{"message": "world"}}'

Instagram Graph API Returning "error_message"=>"Invalid platform app"

Im trying to get authenticate with Instagram Graph API. When I do the following with a curl command it returns my access_token.
When I use HTTParty gem, Instagram Graph API returns the following:
[22] pry(InstagramService)* )
=> {"error_type"=>"OAuthException", "code"=>400, "error_message"=>"Invalid platform app"}
I really tried but I can't see what im doing wrong. Here is my code:
class InstagramService
def self.get_access_token(code)
token_params = {
client_id: ENV['INSTAGRAM_APP_ID'],
client_secret: ENV['INSTAGRAM_APP_SECRET'],
grant_type: "athorization_code",
redirect_uri: ENV['INSTAGRAM_OAUTH_REDIRECT_URL'],
code: code # <-- This is the code sent by Instagram API. Used to get access token.
}
request = HTTParty.post(
"https://api.instagram.com/oauth/access_token",
body: token_params.to_json,
headers: { 'Content-Type' => 'application/json' }
)
end
end
Does anyone know whats wrong? Why am I getting this error instead of the access_token, the same that I get when I use the curl command.
curl -X POST \
https://api.instagram.com/oauth/access_token \
-F client_id=684477648739411 \
-F client_secret=eb8c7... \
-F grant_type=authorization_code \
-F redirect_uri=https://socialsizzle.herokuapp.com/auth/ \
-F code=AQDp3TtBQQ...

When I add security Scheme as JWT in my OpenAPI definition, the "Try it out" feature in UI always returns 401: Unauthorized error

I have the following basic openAPI definition:
openapi: "3.0.0"
info:
description: >-
API which tests service
version: "1.0"
title: Test Service
servers:
- url: /
description: Localhost Server
security:
- bearerAuth: []
paths:
/test:
get:
operationId: app.test
responses:
200:
description: Test
content:
text/plain:
schema:
type: string
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
The Swagger UI shows "Authorize" option where I put the JWT token without "Bearer" keyword, and click on "Try it out". The response is:
{
"detail": "No authorization token provided",
"status": 401,
"title": "Unauthorized",
"type": "about:blank"
}
The curl command has the correct Authorization header, which also doesn't work if I execute it in a terminal.
However, if I remove the security tag from the OpenAPI definition, the "Try it out" as well as the curl command works.
Does anyone know what could be the problem? What is the correct curl command when using JWT security Scheme in OpenAPI?
I'm using JWT authentication in my app and this is my curl that works. I'm trying to figure out how to get OpenApi to generate the proper headers.
curl "${URL}/${ID}/${RESOURCE}" \
-H "Accept: application/json" \
-H "X-Requested-With: XMLHttpRequest" \
-H "Authorization: Bearer ${BEARER_TOKEN}" \
-H "Content-Type: application/json" | python -m json.tool

How to create chat room in ejabberd through rest api?

I know that I can create chat room in ejabberd using command
ejabberdctl create_room room_name muc_service xmpp_domain
and I can send invites to users using command
ejabberdctl send_direct_invitation room_name password reason jid1[:jid2]
Can someone tell me how to do the same using ejabberd rest api ?
I'm using oauth for authentication.
I've done following configuration in ejabberd.yml file
port: 5280
module: ejabberd_http
request_handlers:
"/websocket": ejabberd_http_ws
"/log": mod_log_http
"/oauth": ejabberd_oauth
"/api": mod_http_api
web_admin: true
http_bind: true
register: true
captcha: true
commands_admin_access: configure
commands:
- add_commands:
- user
- status
oauth_expire: 3600
oauth_access: all
and also enabled mod_muc_admin in ejabberd.yml file using
modules:
mod_muc_admin: {}
Use mod_restful module for accessing ejabberd through api. You need to configure below lines in ejabberd.yml if you want to access that module.
mod_restful:
api:
- path: ["admin"]
module: mod_restful_admin
params:
key: "secret"
allowed_commands: [register, unregister,status, add_rosteritem, create_room, send_direct_invitation, set_room_affiliation]
- path: ["register"]
module: mod_restful_register
params:
key: "secret"
They commands that are declared in allowed_commands, only those commands are accessible through api. So in future if you want to access any other commands you need to add here.
once you finished adding ,restart ejabberd and you can access api either with postman or with curl
/*
Data that need to be sent for creating group.
Url : example.com:8088/api/admin/
Content-Type: application/json
{"key": "secret","command": "create_room","args": ["group1","conference.example.com","example.com"]}
*/
Similar like this try for send_direct_invitation too...
To do the api request to create a room,
Do a curl post,
curl -X POST -H "Cache-Control: no-cache" -d '{
"name": "aaaaa",
"service": "bbbbb",
"host": "ccccc"
}' "http://localhost:5280/api/create_room"
Or if you want to add multiple room in a single stoke, add all the room names in a file, say the file name is aaaaa
do a curl as this,
curl -X POST -H "Cache-Control: no-cache" -d '{
"file": "aaaaa"
}' "http://localhost:5280/api/create_rooms_file"

What is content of X-Registry-Auth for Docker push to private registry

What should the content of the X-Registry-Auth header be when pushing a Docker image to a private registry using the REST API? Per Using Docker API to push to private registry, an X-Registry-Auth header is required. https://groups.google.com/forum/#!topic/docker-user/vXcA8fsCNZM suggests that the value should be a base64 encoded JSON string of the form:
{'username': string, 'password': string, 'email': string, 'serveraddress' : string}
After setting suitable environment variables, I did:
XRA=`echo "{\"username\": \"${USERNAME}\", \"password\": \"${PASSWORD}\", \"email\": \"${EMAIL_ADDRESS}\", \"serveraddress\" : \"${SERVER_ADDRESS}\"}" | base64 --wrap=0`
curl -v --request POST --header "X-Registry-Auth: $XRA" http://$DOCKER_HOST/v1/images/$REGISTRY/$NAMESPACE/$REPOSITORY?tag=$TAG
And get a 403 Forbidden response.
Perhaps the problem is just that I don't know what the values should be. How can I determine them? Docker seems to have a way; sudo docker push $REGISTRY/$NAMESPACE/$REPOSITORY:$TAG works just fine.
I had a private nexus docker repo (Docker Api v2), and for me, that was the solution:
XRA=`echo "{ \"username\": \"yourname\", \"password\": \"yourpass\", \"email\": \"youmail#example.org\" }" | base64 --wrap=0`
curl -X POST -d "" -H "X-Registry-Auth: $XRA" http://localhost:4243/images/create?fromImage=private.host:19003/imagename&tag=latest
The following worked for me in node.js (after hours of frustrating trials...):
var authInfo2 = `{\"username\": \"${user}\", \"password\": \"${passwd}\", \"email\": \"${email}\", \"serveraddress\": \"${registry}\"}`
var authInfo = Buffer.from(authInfo2).toString('base64')
var result = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Registry-Auth' : authInfo }
})
I think you're missing two layers in your encoding. The actual code that generates the header (from github)
def encode_header(auth):
auth_json = json.dumps(auth).encode('ascii')
return base64.b64encode(auth_json)
def encode_full_header(auth):
""" Returns the given auth block encoded for the X-Registry-Config header.
"""
return encode_header({'configs': auth})
So you need an outer map of { 'configs': [ array of auth entries ] }, all json-then-base64 encoded.
To check your authentication environment variables issue
docker login --username $USERNAME --password $PASSWORD --email $EMAIL_ADDRESS $SERVER_ADDRESS
If they are correct you'll see "Login Succeeded".
I suspect $NAMESPACE should match $USERNAME.
Try using v1.13 as the version instead of v1.

Resources