flask_restx - api.expect from two sources for swagger - flask

Hei there!
I have a flask restx api and I have an endpoint that essentially needs to do the following
filters = api.model('filters', {
x = fields.Raw('x')
}
parser = reqparse.RequestParser()
parser.add_argument('b', type=int, location='args')
class Process(Resource):
#api.expect(filters)
#api.expect(parser)
def get()
.
.
why?
I have a large set of endpoints that all accept the same filter design, but some endpoints also need query parameters
The code works just fine, I can access the json payload and the query parameters inside the method.
The problem
I need everything documented by swagger but I need to "mix" the api.model object with the parser object into the #api.expect()

#api.expect(filters,parser) should work

Related

how to make list as a parameter in the [GET, POST] methods

I'm working on a data set of 'Human activity recognition using smart phones'
would like to link the data with an API using flask, which can be reflected on a web page.
so I want to create a list to take all the human body movements in the data set as a parameters in a list which If I pass it to the predict route in the flask through a web page enables the model to predict the human body activity.
Put the list in a JSON object. You can use jsonify for this.
#app.route('/get_fruits')
def get_fruits():
response = {"fruits": ["apple", "banana"]}
return jsonify(response)

Flask Swagger documentation query parameter GET required

I'm using Swagger documentation with my flask project to document the endpoints and parameters.
To define the query parameters for an endpoint I'm doing:
#api.doc(params={
'name_query_parameter': 'Description'})
I wanted to know if it's possible for that parameter to show in the docs as "required", like it does for when the parameter is part of the path (home/name_query_parameter/something/something).
Looking into the documentation I only found the following:
#api.expect()
#api.doc(body=the_defined_payload)
But this implies for the information to be on the body, I can't have that with a GET request. Plus, I want it as a query parameter, not as part of the payload.
Is this possible at all?
Thanks.
The final solution to this is as follows, thanks to Mikhail for commenting about the parser. I have to admit though, documentation is not the best for flask-restplus.
I used the params part to make sure the fields appear in the docs along with a description and the parser for custom validation and to make the field appear as required even though it is located in the URL as params.
parser = reqparse.RequestParser()
parser.add_argument('superimportant',
type=inputs.boolean, location='args', required=True)
parser.add_argument('something', type=custom_validation_parser, location='args')
class MySuperClassResource(Resource):
#api.doc(parser=categories_by_retailer_parser,
params={"superimportant": "Description of this important field",
"something": "bla bla"
})
def get(self, blable):
parser.parse_args()
pass
The custom_validation_parser is just a method that allows custom validation, like for empty values. The format of that method is as follows. (It must return the value you want to access, and if there's . problem, raise a ValueError).
def custom_validation_parser(value):
if not value:
raise ValueError("Must not be empty.")
return value

How to store values (given by user via postmain) in the variables with POST method using Django restful services

I need help to store values for x , y, z into the variables with Django restful services. With the php this can be done with similar to below code.
var1 = $_POST['x'];
var2 = $_POST['y'];
var2 = $_POST['z'];
I have started learning Django (mainly Restful API) and easily learned to do many other things (which is not that easy to do with PHP) with Django such as insert, del, update data configured swagger and admin but I did not find a way to store value in variable. I want to store these variables to 'return' the kind of data that is being requested (these variable will have value something like that).
In the rest frameworks's apiview, you can access your data using request.data
request.data is parsed content of the request body and includes file and non-file inputs as well.
doc: https://www.django-rest-framework.org/api-guide/requests/
Note : good to be aware what is the difference between Django's HttpRequest class and rest framework's Request class ( see in the doc link mentioned above ).
As far as I could understand your question, you are trying to fetch POST data in your view. So you can access the data from the request object in your view class, for eg:
class YourView(APIView):
def post(self, request):
data = request.data
var1 = data['x']
var2 = data['y']
var3 = data['z']
# do something with these variables....
# or if you have serializer class
ser = YourSerializer(data=request.data)
.....
Hope it helps.

Testing Graphene-Django

Currently I am investigating using graphene to build my Web server API. I have been using Django-Rest-Framework for quite a while and want to try something different.
I have figured out how to wire it up with my existing project and I can test the query from Graphiql UI, by typing something like
{
industry(id:10) {
name
description
}
}
Now, I want to have the new API covered by Unit/integration tests. And here the problem starts.
All the documentation/post I am checking on testing query/execution on graphene is doing something like
result = schema.execute("{industry(id:10){name, description}}")
assertEqual(result, {"data": {"industry": {"name": "Technology", "description": "blab"}}}
My point is that the query inside execute() is just a big chunk of text and I don't know how I can maintain it in the future. I or other developer in the future has to read that text, figure out what it means and update it if needed.
Is that how this supposed to be? How do you guys write unit test for graphene?
I've been writing tests that do have a big block of text for the query, but I've made it easy to paste in that big block of text from GraphiQL. And I've been using RequestFactory to allow me to send a user along with the query.
from django.test import RequestFactory, TestCase
from graphene.test import Client
def execute_test_client_api_query(api_query, user=None, variable_values=None, **kwargs):
"""
Returns the results of executing a graphQL query using the graphene test client. This is a helper method for our tests
"""
request_factory = RequestFactory()
context_value = request_factory.get('/api/') # or use reverse() on your API endpoint
context_value.user = user
client = Client(schema) # Note: you need to import your schema
executed = client.execute(api_query, context_value=context_value, variable_values=variable_values, **kwargs)
return executed
class APITest(TestCase):
def test_accounts_queries(self):
# This is the test method.
# Let's assume that there's a user object "my_test_user" that was already setup
query = '''
{
user {
id
firstName
}
}
'''
executed = execute_test_client_api_query(query, my_test_user)
data = executed.get('data')
self.assertEqual(data['user']['firstName'], my_test_user.first_name)
...more tests etc. etc.
Everything between the set of ''' s ( { user { id firstName } } ) is just pasted in from GraphiQL, which makes it easier to update as needed. If I make a change that causes a test to fail, I can paste the query from my code into GraphQL, and will often fix the query and paste a new query back into my code. There is purposefully no tabbing on this pasted-in query, to facilitate this repeated pasting.

Pulling data from datastore and converting it in Json in python(Google Appengine)

I am creating an apllication using google appengine, in which i am fetching a data from the website and storing it in my Database (Data store).Now whenever user hits my application url as "application_url\name =xyz&city= abc",i am fetching the data from the DB and want to show it as json.Right now i am using a filter to fetch data based on the name and city but getting output as [].I dont know how to get data from this.My code looks like this:
class MainHandler(webapp2.RequestHandler):
def get(self):
commodityname = self.request.get('veg',"Not supplied")
market = self.request.get('market',"No market found with this name")
self.response.write(commodityname)
self.response.write(market)
query = commoditydata.all()
logging.info(commodityname)
query.filter('commodity = ', commodityname)
result = query.fetch(limit = 1)
logging.info(result)
and the db structure for "commoditydata" table is
class commoditydata(db.Model):
commodity= db.StringProperty()
market= db.StringProperty()
arrival= db.StringProperty()
variety= db.StringProperty()
minprice= db.StringProperty()
maxprice= db.StringProperty()
modalprice= db.StringProperty()
reporteddate= db.DateTimeProperty(auto_now_add = True)
Can anyone tell me how to get data from the db using name and market and covert it in Json.First getting data from db is the more priority.Any suggestions will be of great use.
If you are starting with a new app, I would suggest to use the NDB API rather than the old DB API. Your code would look almost the same though.
As far as I can tell from your code sample, the query should give you results as far as the HTTP query parameters from the request would match entity objects in the datastore.
I can think of some possible reasons for the empty result:
you only think the output is empty, because you use write() too early; app-engine doesn't support streaming of response, you must write everything in one go and you should do this after you queried the datastore
the properties you are filtering are not indexed (yet) in the datastore, at least not for the entities you were looking for
the filters are just not matching anything (check the log for the values you got from the request)
your query uses a namespace different from where the data was stored in (but this is unlikely if you haven't explicitly set namespaces anywhere)
In the Cloud Developer Console you can query your datastore and even apply filters, so you can see the results with-out writing actual code.
Go to https://console.developers.google.com
On the left side, select Storage > Cloud Datastore > Query
Select the namespace (default should be fine)
Select the kind "commoditydata"
Add filters with example values you expect from the request and see how many results you get
Also look into Monitoring > Log which together with your logging.info() calls is really helpful to better understand what is going on during a request.
The conversion to JSON is rather easy, once you got your data. In your request handler, create an empty list of dictionaries. For each object you get from the query result: set the properties you want to send, define a key in the dict and set the value to the value you got from the datastore. At the end dump the dictionary as JSON string.
class MainHandler(webapp2.RequestHandler):
def get(self):
commodityname = self.request.get('veg')
market = self.request.get('market')
if commodityname is None and market is None:
# the request will be complete after this:
self.response.out.write("Please supply filters!")
# everything ok, try query:
query = commoditydata.all()
logging.info(commodityname)
query.filter('commodity = ', commodityname)
result = query.fetch(limit = 1)
logging.info(result)
# now build the JSON payload for the response
dicts = []
for match in result:
dicts.append({'market': match.market, 'reporteddate': match.reporteddate})
# set the appropriate header of the response:
self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
# convert everything into a JSON string
import json
jsonString = json.dumps(dicts)
self.response.out.write( jsonString )