Deploy multiple web services, i.e. multiple wsdl files, in python - python

I'm creating web services in python using Spyne based on this example. However, all my services are combined into one wsdl file locating at http://localhost:8000/?wsdl. I'm looking for another way to deploy each web service separately in a single wsdl file, e.g.
http://localhost:8000/service1/?wsdl and http://localhost:8000/service2?wsdl

Spyne has a WsgiMounter class for this:
from spyne.util.wsgi_wrapper import WsgiMounter
app1 = Application([SomeService], tns=tns,
in_protocol=Soap11(), out_protocol=Soap11())
app2 = Application([SomeOtherService], tns=tns,
in_protocol=Soap11(), out_protocol=Soap11())
wsgi_app = WsgiMounter({
'app1': app1,
'app2': app2,
})
Now you can pass wsgi_app to the Wsgi implementation that you're using the same way you'd pass a WsgiApplication instance.
Your Wsgi implementation also would definitely have a similar functionality, you can also use that in case e.g. you need to serve something for the root request instead of an empty 404 request.
An up-to-date fully working example can be found at: https://github.com/plq/spyne/blob/master/examples/multiple_protocols/server.py
Please note that you can't use one Service class with multiple applications. If you must do that, you can do it like this:
def SomeServiceFactory():
class SomeService(ServiceBase):
#rpc(Unicode, _returns=Unicode)
def echo_string(ctx, string):
return string
return SomeService
and use the SomeServiceFactory() call for every Application instance.
e.g.
app1 = Application([SomeServiceFactory()], tns=tns,
in_protocol=Soap11(), out_protocol=Soap11())
app2 = Application([SomeServiceFactory()], tns=tns,
in_protocol=Soap11(), out_protocol=Soap11())
Hope that helps.

Related

How to mock a rest API in python

I have a application running which some where in the midst uses some rest API call. Now for stress test I want to replace this API call with some mock server. Is there any way to do it.
Let me try to put it programmatically so it gets some clarity. I've a some server running at port say 8080
# main server
from flask import Flask
from myapp import Myapp
app = Flask(__name__)
#app.route("/find_solution", methods=["GET"])
def solution() :
return app.sol.find_solution(), 200
def start():
app.sol = Myapp()
return app
Now this Myapp
#myapp
import requests
class Myapp:
def __init__():
self.session = requests.Session()
def find_solution():
myparameters = {"Some parameter that I filled"}
return self.session.request('GET', 'http://api.weatherstack.com/current', params=myparameters)
Now here I want to replace behavior of http://api.weatherstack.com/current without modifying code. i.e some way where I can replace call to http:api.weatherstack.com/current to my local system server.
Any help of lead is appreciated. I am using ubuntu 20.04
So for your scenario if you want to test your api flask comes with mock test client feature.
test_client = app.test_client()
test_client.post('/find_solution', headers={"Content-Type": "application/json"}, data=data)
So for this scenario you can create test cases and get test client instance inside your test case and perform tests at api level. This is a light weight test method rather than the one proposed by you
Refer to the following link for official flask documentation
https://flask.palletsprojects.com/en/1.1.x/testing/#keeping-the-context-around
Cheers

Python REST-API with Flask-RestX and JavaScript REST-Client served together

I run this example: https://flask-restx.readthedocs.io/en/latest/example.html
(A Python REST-API with Flask-RESTX)
Code snippet
app = Flask(__name__)
api = Api(app, ...)
ns = api.namespace('todos', ...)
#ns.route('/')
...
#ns.route('/<int:id>')
...
Result
I get the following URLs for the REST-API:
http://127.0.0.1:5000 -> Swagger Documentation
http://127.0.0.1:5000/swagger.json
http://127.0.0.1:5000/todos/
http://127.0.0.1:5000/todos/{id}
Question
I would like to implement a Webclient with Javascript, which should be reached under following URLs:
http://127.0.0.1:5000 -> index.html
http://127.0.0.1:5000/style.css
http://127.0.0.1:5000/app.js
The URLs for the REST-API should change to:
http://127.0.0.1:5000/api -> Swagger Documentation
http://127.0.0.1:5000/api/swagger.json
http://127.0.0.1:5000/api/todos/
http://127.0.0.1:5000/api/todos/{id}
How can I expand the example to generate the wanted URLs?
Not sure if you have gotten an answer by now. I often clone the below github project for flask restx boilerplate. It is designed as a rest boilerplate to help get you up and running.
https://github.com/cosmic-byte/flask-restplus-boilerplate
The templates and static files can be added to the application and to the controllers to host the pages. Added the below documentation for the static pages. Every this should be there to get you running with a full site
https://flask.palletsprojects.com/en/1.1.x/tutorial/static/
You can wrap flask-restx application with flask.Blueprint to move swagger logic under a specific url_path.
The following example shows how this can be achieved:
import flask
import flask_restx
APP = flask.Flask("my-app")
api_bp = flask.Blueprint("api", __name__, url_prefix="/api")
API = flask_restx.Api(api_bp)
APP.register_blueprint(api_bp)
NAMESPACE = API.namespace("todos")
#NAMESPACE.route("/")
class TODOSAPI(flask_restx.Resource):
def get(self):
return ['todo-1', 'todo-2']

Is there a better way to use rollbar error reporting with flask?

I just came across rollbar and wanted to include it in my Python project.
This is the standard way in which I am told to implement rollbar from the website.
import rollbar
rollbar.init('KEY')
try:
a = s
except:
rollbar.report_exc_info()
Is there a better way to implement this without going through all my try except blocks and replacing them with rollbar.report_exc_info()
Can there be a decorator implementation for this?
My current project is a Flask app that provides API's to end users.
Here's an example for rollbar integration in Flask apps.
https://github.com/rollbar/rollbar-flask-example/blob/master/hello.py
#app.before_first_request
def init_rollbar():
"""init rollbar module"""
rollbar.init(
# access token for the demo app: https://rollbar.com/demo
'fc316ac1f7404dc28af26d5baed1416c',
# environment name
'flasktest',
# server root directory, makes tracebacks prettier
root=os.path.dirname(os.path.realpath(__file__)),
# flask already sets up logging
allow_logging_basic_config=False)
# send exceptions from `app` to rollbar, using flask's signal system.
got_request_exception.connect(rollbar.contrib.flask.report_exception, app)

Combining resources in Python with Flask

I' trying to combine two independent Flask apps like the example below:
from geventwebsocket import WebSocketServer, Resource
...
server = WebSocketServer(('', 8080), Resource({
'/': frontend,
'/one': flask_app_one,
'/two': flask_app_two}))
server.serve_forever()
Inside each Flask app I declare the full path, isn't that suppose to be relative path, inside flask_app_one:
from flask import Flask
app = Flask(__name__)
#app.route('/one/ping')
def ping():
return 'hello\n'
Why I should specify in #app.route('/one/ping') instead of just #app.route('/ping') since all traffic to /one will be forwarded to the corresponding app?
Let me know if you need any additional info I kept my example clean
Thank you
Finally I have managed to do it with the so called Application Dispatching and the resources found in this page:
http://flask.pocoo.org/docs/0.10/patterns/appdispatch/#app-dispatch
Thanks

Calling flask restful API resource methods

I'm creating an API with Flask that is being used for a mobile platform, but I also want the application itself to digest the API in order to render web content. I'm wondering what the best way is to access API resource methods inside of Flask? For instance if I have the following class added as a resource:
class FooAPI(Resource):
def __init__(self):
# Do some things
super(FooAPI, self).__init__()
def post(self, id):
#return something
def get(self):
#return something
api = Api(app)
api.add_resource(FooAPI, '/api/foo', endpoint = 'foo')
Then in a controller I want:
#app.route("/bar")
def bar():
#Get return value from post() in FooAPI
How do I get the return value of post() from FooAPI? Can I do it somehow through the api variable? Or do I have to create an instance of FooAPI in the controller? It seems like there has to be an easy way to do this that I'm just not understanding...
The obvious way for your application to consume the API is to invoke it like any other client. The fact that the application would be acting as a server and a client at the same time does not matter, the client portion can place requests into localhost and the server part will get them in the same way it gets external requests. To generate HTTP requests you can use requests, or urllib2 from the standard library.
But while the above method will work just fine it seems overkill to me. In my opinion a better approach is to expose the common functionality of your application in a way that both the regular application and the API can invoke. For example, you could have a package called FooLib that implements all the shared logic, then FooAPI becomes a thin wrapper around FooLib, and both FooAPI and FooApp call FooLib to get things done.
Another approach is to have both the app and API in the same Flask(-RESTful) instance. Then, you can have the app call the API methods/functions internally (without HTTP). Let's consider a simple app that manages files on a server:
# API. Returns filename/filesize-pairs of all files in 'path'
#app.route('/api/files/',methods=['GET'])
def get_files():
files=[{'name':x,'size':sys.getsizeof(os.path.join(path,x))} for x in os.listdir(path)]
return jsonify(files)
# app. Gets all files from the API, uses the API data to render a template for the user
#app.route('/app/files/',methods=['GET'])
def app_get_files():
response=get_files() # you may verify the status code here before continuing
return render_template('files.html',files=response.get_json())
You can push all your requests around (from the API to the app and back) without including them in your function calls since Flask's request object is global. For example, for an app resource that handles a file upload, you can simply call:
#app.route('/app/files/post',methods=['POST'])
def app_post_file():
response=post_file()
flash('Your file was uploaded succesfully') # if status_code==200
return render_template('home.html')
The associated API resource being:
#app.route('/api/files/',methods=['POST'])
def post_file():
file=request.files['file']
....
....
return jsonify({'some info about the file upload'})
For large volumes of application data, though, the overhead of wrapping/unwrapping JSON makes Miguel's second solution preferrable.
In your case, you would want to call this in your contoller:
response=FooAPI().post(id)
I managed to achieve this, sometimes API's get ugly, in my case, I need to recursively call the function as the application has a extremely recursive nature (a tree). Recursive functions itself are quite expensive, recursive HTTP requests would be a world of memory and cpu waste.
So here's the snippet, check the third for loop:
class IntentAPI(Resource):
def get(self, id):
patterns = [pattern.dict() for pattern in Pattern.query.filter(Pattern.intent_id == id)]
responses = [response.dict() for response in Response.query.filter(Response.intent_id == id)]
return jsonify ( { 'patterns' : patterns, 'responses' : responses } )
def delete(self, id):
for pattern in Pattern.query.filter(Pattern.intent_id == id):
db.session.delete(pattern)
for response in Response.query.filter(Response.intent_id == id):
db.session.delete(response)
for intent in Intent.query.filter(Intent.context == Intent.query.get(id).set_context):
self.delete(intent.id) #or IntentAPI.delete(self, intent.id)
db.session.delete(Intent.query.get(id))
db.session.commit()
return jsonify( { 'result': True } )

Categories