I'm trying to host the Swagger UI of Flask Restplus on Heroku server. It builds successfully and when checked in the logs of the heroku, even there it says "Build succeeded".
But the problem is when I check the actual hosting there's just a msg on the page saying
No API definition provided.
Btw the swagger-UI loads successfully on the browser when run locally.
Following is a sample code snipet for swagger-ui
from flask import Flask
from flask_restplus import Resource, Api
import os
app = Flask(__name__)
api = Api(app)
#api.route('/hello')
class HelloWorld(Resource):
def get(self):
return {'hello': 'world'}
if __name__ == '__main__':
port = int(os.environ.get("PORT", 5000))
app.run(host="0.0.0.0", port=port, debug=True)
So what am I doing wrong here? Is there any way that you can host a simple minimal flask_restplus swagger-UI on heroku ? Any help is appreciated, thanks.
EDIT
Following is the content of the swagger.json
{
"swagger": "2.0",
"basePath": "/",
"paths": {
"/hello": {
"get": {
"responses": {
"200": {
"description": "Success"
}
},
"operationId": "get_hello_world",
"tags": [
"default"
]
}
}
},
"info": {
"title": "API",
"version": "1.0"
},
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"tags": [
{
"name": "default",
"description": "Default namespace"
}
],
"responses": {
"ParseError": {
"description": "When a mask can't be parsed"
},
"MaskError": {
"description": "When any error occurs on mask"
}
}
}
Also if it helps, this is what's inside the Procfile
web: python app.py
Posting what worked for me, just in case if someone has the same concern in future.
I changed the Procfile from
web: python app.py
to
web: gunicorn app:app
and then the swagger-UI first page also started showing up on heroku. Earlier the endpoints were still accessible but the first page ie. the swagger-UI page wasn't showing up. But making this change got it working.
Related
I am using the python slack bolt. https://api.slack.com/start/building/bolt-python#create
I created the example in the link and was able to make a home tab page but I want to create a modal from a message in a channel, not a home page view. I have looked everywhere for a basic example but I can't get any MODALS to work with what I have learned from slack's own documentation. This is the only examples I can find (which came from slack's own documentation after you read the starting out page).
Here is the test example that works but shows up with a home page instead of a modal:
SLACK_BOT_TOKEN="slackbottokenstring"
SLACK_SIGNING_SECRET="slacksigningsecretstring"
import os
# Use the package we installed
from slack_bolt import App
# Initializes your app with your bot token and signing secret
app = App(
token = SLACK_BOT_TOKEN,
signing_secret = SLACK_SIGNING_SECRET
# token=os.environ.get("SLACK_BOT_TOKEN"),
# signing_secret=os.environ.get("SLACK_SIGNING_SECRET")
)
# Add functionality here
#app.event("app_home_opened")
def update_home_tab(client, event, logger):
try:
# views.publish is the method that your app uses to push a view to the Home tab
client.views_publish(
# the user that opened your app's app home
user_id=event["user"],
# the view object that appears in the app home
view={
"type": "home",
"callback_id": "home_view",
# body of the view
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Welcome to your _App's Home_* :tada:"
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "This button won't do much for now but you can set up a listener for it using the `actions()` method and passing its unique `action_id`. See an example in the `examples` folder within your Bolt app."
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Click me!"
}
}
]
}
]
}
)
except Exception as e:
logger.error(f"Error publishing home tab: {e}")
# Start your app
if __name__ == "__main__":
app.start(port=int(os.environ.get("PORT", 3000)))
And that works:
But if I try to change it to a modal, it fails:
CODE:
#app.event("app_home_opened")
def update_home_tab(client, event, logger):
try:
# views.publish is the method that your app uses to push a view to the Home tab
client.views_publish(
# the user that opened your app's app home
user_id=event["user"],
# the view object that appears in the app home
view={
"type": "modal",
"callback_id": "modal-identifier",
"title": {
"type": "plain_text",
"text": "Just a modal"
},
"blocks": [
{
"type": "section",
"block_id": "section-identifier",
"text": {
"type": "mrkdwn",
"text": "*Welcome* to ~my~ Block Kit _modal_!"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Just a button",
},
"action_id": "button-identifier",
}
}
],
}
)
Error:
127.0.0.1 - - [14/Aug/2022 15:21:15] "POST /slack/events HTTP/1.1" 200 -
Error publishing home tab: The request to the Slack API failed. (url: https://www.slack.com/api/views.publish)
The server responded with: {'ok': False, 'error': 'invalid_arguments', 'response_metadata': {'messages': ['[ERROR] failed to match all allowed schemas [json-pointer:/view]', '[ERROR] unsupported type: modal [json-pointer:/view/type]']}}
I am following the view structure design in a json object like it says here: https://api.slack.com/surfaces/modals/using#composing_views
I figured out what I had to do but it was kinda annoying, I want to just say that first. There are a couple reasons as to why it was annoying to figure out.
There is no direct python example from the website, BUT slack does have a github where they show a modal example.
Using specifically Modals require than just making text blocks in a chat. It requires some weird thing called a trigger_id which you get from initiating a specific response that would cause slack to send an object over to your endpoint. The problem is that there is no example of this. If you are going through slack's tutorial, they ONLY show you how to create a url for making a bot that event listens and responds to messages. You can make your own url using flask but since I am using the bolt slack module, they wrap there own stuff around flask which makes it hard to make basic decorators for flask. - In other words, the slack documentation is super confusing for modals and they don't have any real examples for modals with bolt python.
after doing days of research in my spare time, I was finally able to get an example working where you can COPY AND PASTE this code. You just need your bot token secret and signing key which you can set in your environment or as a string if you are just testing around in your local computer.
SLACK_BOT_TOKEN="slackbottokenstring"
SLACK_SIGNING_SECRET="slacksigningsecretstring"
import os
# Use the package we installed
from slack_bolt import App
from slack_bolt.adapter.flask import SlackRequestHandler
from flask import Flask, request
flask_app = Flask(__name__)
# Initializes your app with your bot token and signing secret
app = App(
token = SLACK_BOT_TOKEN,
signing_secret = SLACK_SIGNING_SECRET
# token=os.environ.get("SLACK_BOT_TOKEN"),
# signing_secret=os.environ.get("SLACK_SIGNING_SECRET")
)
handler = SlackRequestHandler(app)
#flask_app.route("/slack/events", methods=["POST"])
def slack_events():
return handler.handle(request)
#app.shortcut("SearchMessagesID")
def handle_shortcuts(ack, body, logger,client):
ack()
logger.info(body)
print(body)
res = client.views_open(
trigger_id=body["trigger_id"],
view={
"type": "modal",
"callback_id": "modal-identifier",
"title": {
"type": "plain_text",
"text": "Just a modal"
},
"blocks": [
{
"type": "section",
"block_id": "section-identifier",
"text": {
"type": "mrkdwn",
"text": "*Welcome* to ~my~ Block Kit _modal_!"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Just a button",
},
"action_id": "button-identifier",
}
}
],
}
)
# Start your app
if __name__ == "__main__":
app.start(port=int(os.environ.get("PORT", 3000)))
Im trying testing if its possible to run two functions in one Azure function app one running FastAPI and the other one running Flask.
I tried to specify a different route for each function.json file but to no avail.
# FastAPI function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post",
"patch",
"delete"
],
"route": "/api/{*route}"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
# __init__.py
import logging
import azure.functions as func
from fastapi import FastAPI
app = FastAPI()
#app.get("/api/hello/")
async def hello():
return {'message': 'Hello World!'}
def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
return func.AsgiMiddleware(app).handle(req, context)
and
# Flask function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post",
"patch",
"delete"
],
"route": "/flask/{*route}"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
#__init__.py
import logging
import azure.functions as func
from flask import Flask
app = Flask(__name__)
#app.route("/home/")
def home():
return "<p>Hello, World!</p>"
def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
return func.WsgiMiddleware(app.wsgi_app).handle(req, context)
If you deploy using GitHub, you can run two functions in one Azure function app.
To do this push the required code in a GitHub repository.
Then in the azure function go to the development center section.
Then select source as GitHub it will ask you to login and for
permissions.
After granting them select the repository (the repository must be
private) and then select branch then click save.
Refresh the function app and you will see the triggers in the
function section
refer the following documentation for further explaination
I have created an Azure Function base on a custom image (docker) using VS Code.
I used the deployment feature of VS code to deploy it to azure and everything was fine.
My function.json file specifies anonymous auth level:
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
Why an I still getting the 401 unauthorized error?
Thanks
Amit
I changed my authLevel from function to anonymous and it finally worked!
Below methods can fix 4XX errors in our function app:
Make sure you add all the values from Local.Settings.json file to Application settings (FunctionApp -> Configuration -> Application Settings)
Check for CORS in your function app. Try adding “*” and saving it.. reload the function app and try to run it.
(Any request made against a storage resource when CORS is enabled must either have a valid authorization header or must be made against a public resource.)
When you make your request to your function, you may need to pass an authorization header with key 'x-functions-key' and value equal to either your default key for all functions (Function App > App Keys > default in the Azure portal) or a key specific to that function (Function App > Functions > [specific function] > Function Keys > default in Azure Portal).
I'm making an action-on-google assistant. I'm able to receive the request in JSON format by using Flask to establish webhook in Python. But I've no idea how to send the response back to the assistant.
enter image description here
enter image description here
import os, sys
from flask import Flask, request, send_from_directory, make_response
from googleactions import AppRequest, AppResponse, SimpleResponse
class operation():
def justPrint(self):
print("Hi dear user")
print(AppResponse('告訴我故事發生什麼事吧').json())
app = Flask(__name__)
#app.route('/', methods=['GET'])
def verify():
return "hello world"
#app.route('/', methods=['POST'])
def webhook():
req = request.get_json()
print(req)
op = operation()
getattr(op, req['handler']['name'])()
return 'ok', 200
if __name__ == "__main__":
app.run(debug=True, port=8080)
Your Flask server should return a JSON response in the correct format. It looks like you may be using the googleactions package, but unfortunately that package seems to be out-of-date with the response format expected by Actions Builder.
You should consult the JSON schema for the HandlerResponse type. As it is JSON schema, you can use a tool like Quicktype to generate the appropriate classes for additional syntax support.
The schema file also includes definitions for the internal types.
"HandlerResponse": {
"description": "Represents a response sent from a developer's fulfillment to Actions on\nGoogle.",
"type": "object",
"properties": {
"prompt": {
"description": "Optional. Represents the prompts to be sent to the user, these prompts\nwill be appended to previously added messages unless explicitly\noverwritten.",
"$ref": "#/definitions/Prompt"
},
"scene": {
"description": "Optional. Represents the current and next scene. If `Scene.next` is set\nthe runtime will immediately transition to the specified scene.",
"$ref": "#/definitions/Scene"
},
"session": {
"description": "Optional. Describes data for the current session, session\nparameters can be created, updated, or removed by the fulfillment.",
"$ref": "#/definitions/Session"
},
"user": {
"description": "Optional. Use to specify user parameters to send back.",
"$ref": "#/definitions/User"
},
"home": {
"description": "Optional. Used to specify parameters related to the HomeGraph structure\nthat the target device belongs to. See\nhttps://developers.google.com/actions/smarthome/concepts/homegraph.",
"$ref": "#/definitions/Home"
},
"device": {
"description": "Optional. Use to move between Assistant devices the user has access to.",
"$ref": "#/definitions/Device"
},
"expected": {
"description": "Optional. Describes the expectations for the next dialog turn.",
"$ref": "#/definitions/Expected"
}
}
},
I'm getting a KeyError while using the JSON library in Python (with Flask)
I don't really understand it.
KeyError: 'sites'
is the error I'm getting
JSON Code:
{
"sites": {
"example-site": {
"domains": [
"example.pagehost.com",
"127.0.0.1:5000"
],
"pages": {
"index/": "index.html"
},
"index": "index.html",
"owner": "Bevan",
"id": "example-site"
}
}
}
Python Code:
global sites_json
fsite = ""
print("Finding site")
for site in sites_json['sites']:
for domain in site['domains']:
if domain == host:
fsite = site
print("Found site")
break
The infringing line appears to be the for site in sites_json['sites']
May someone who knows what is going on please help?
After some messing around, it turns out that I was launching my Flask app through the python3 -m flask run command, which skipped my JSON file's initialisation steps. When I launch through the python3 app.py command, it works correctly!