Merge branch 'master-rest-api-issues' into 'master'

[FIX] Fixes REST API issues #70, #71 and #73 and add basic guideline of Rest API on description page

See merge request flectra-hq/flectra!70
This commit is contained in:
Parthiv Patel 2018-05-31 12:27:52 +00:00
commit 846520e5d6
3 changed files with 438 additions and 128 deletions

View File

@ -55,108 +55,100 @@ def eval_json_to_data(modelname, json_data, create=True):
return values
def object_read(modelname, default_domain, status_code,
post={}):
json_data = post
domain = default_domain or []
field = []
def object_read(model_name, params, status_code):
domain = []
fields = []
offset = 0
limit = None
order = None
if 'filters' in json_data:
domain += ast.literal_eval(json_data['filters'])
elif 'field' in json_data:
field += ast.literal_eval(json_data['field'])
elif 'offset' in json_data:
offset = int(json_data['offset'])
elif 'limit' in json_data:
limit = int(json_data['limit'])
elif 'order' in json_data:
order = json_data['order']
else:
pass
# Search Read object:
data = request.env[modelname].search_read(domain, offset=offset, limit=limit, order=order)
return valid_response(status=status_code,
data={
'count': len(data), 'results': data
})
if 'filters' in params:
domain += ast.literal_eval(params['filters'])
if 'field' in params:
fields += ast.literal_eval(params['field'])
if 'offset' in params:
offset = int(params['offset'])
if 'limit' in params:
limit = int(params['limit'])
if 'order' in params:
order = params['order']
def object_read_one(modelname, id, status_code):
try:
id = int(id)
except:
pass
if not id:
return invalid_object_id()
data = request.env[modelname].search_read(domain=[('id', '=', id)])
data = request.env[model_name].search_read(domain=domain, fields=fields, offset=offset, limit=limit, order=order)
if data:
return valid_response(status_code, data)
return valid_response(status=status_code, data={
'count': len(data),
'results': data
})
else:
return object_not_found()
return object_not_found_all(model_name)
def object_create_one(modelname, data, status_code):
rdata = request.httprequest.stream.read().decode('utf-8')
json_data = json.loads(rdata)
vals = eval_json_to_data(modelname, json_data)
if data:
vals.update(data)
def object_read_one(model_name, rec_id, params, status_code):
fields = []
if 'field' in params:
fields += ast.literal_eval(params['field'])
try:
res = request.env[modelname].create(vals)
flectra_error = ''
rec_id = int(rec_id)
except Exception as e:
res = None
flectra_error = e
rec_id = False
if not rec_id:
return invalid_object_id()
data = request.env[model_name].search_read(domain=[('id', '=', rec_id)], fields=fields)
if data:
return valid_response(status=status_code, data=data)
else:
return object_not_found(rec_id, model_name)
def object_create_one(model_name, data, status_code):
try:
res = request.env[model_name].create(data)
except Exception as e:
return no_object_created(e)
if res:
return valid_response(status_code, {'id': res.id})
else:
return no_object_created(flectra_error)
def object_update_one(modelname, id, status_code):
def object_update_one(model_name, rec_id, data, status_code):
try:
id = int(id)
except:
id = None
if not id:
return invalid_object_id()
rdata = request.httprequest.stream.read().decode('utf-8')
json_data = ast.literal_eval(rdata)
vals = eval_json_to_data(modelname, json_data, create=False)
try:
res = request.env[modelname].browse(id).write(vals)
flectra_error = ''
rec_id = int(rec_id)
except Exception as e:
res = None
flectra_error = e
if res:
return valid_response(status_code, 'Record Updated '
'successfully!')
else:
return no_object_updated(flectra_error)
rec_id = None
def object_delete_one(modelname, id, status_code):
try:
id = int(id)
except:
id = None
if not id:
if not rec_id:
return invalid_object_id()
try:
res = request.env[modelname].browse(id).unlink()
flectra_error = ''
res = request.env[model_name].search([('id', '=', rec_id)])
if res:
res.write(data)
else:
return object_not_found(rec_id, model_name)
except Exception as e:
res = None
flectra_error = e
return no_object_updated(e)
if res:
return valid_response(status_code, 'Record Successfully '
'Deleted!')
else:
return no_object_deleted(flectra_error)
return valid_response(status_code, {'desc': 'Record Updated successfully!', 'update': True})
def object_delete_one(model_name, rec_id, status_code):
try:
rec_id = int(rec_id)
except Exception as e:
rec_id = None
if not rec_id:
return invalid_object_id()
try:
res = request.env[model_name].search([('id', '=', rec_id)])
if res:
res.unlink()
else:
return object_not_found(rec_id, model_name)
except Exception as e:
return no_object_deleted(e)
if res:
return valid_response(status_code, {'desc': 'Record Successfully Deleted!', 'delete': True})
def check_valid_token(func):
@ -284,7 +276,7 @@ class ControllerREST(http.Controller):
# Successful response:
return valid_response(
200,
{}
{"desc": 'Token Successfully Deleted', "delete": True}
)
@http.route([
@ -295,45 +287,27 @@ class ControllerREST(http.Controller):
@check_valid_token
def restapi_access_token(self, model_name=False, id=False, **post):
Model = request.env['ir.model']
Model_ids = Model.sudo().search([('model', '=', model_name),
('rest_api', '=', True)])
if Model_ids:
return getattr(self, '%s_data' % (
request.httprequest.method).lower())(
model_name=model_name, id=id, **post)
return object_not_found()
Model_id = Model.sudo().search([('model', '=', model_name)], limit=1)
def get_data(self, model_name=False, id=False, **post):
if Model_id:
if Model_id.rest_api:
return getattr(self, '%s_data' % (
request.httprequest.method).lower())(
model_name=model_name, id=id, **post)
else:
return rest_api_unavailable(model_name)
return modal_not_found(model_name)
def get_data(self, model_name=False, id=False, **get):
if id:
return object_read_one(
modelname=model_name,
id=id,
status_code=200,
)
return object_read(
modelname=model_name,
default_domain=[],
status_code=200,
post=post
)
return object_read_one(model_name, id, get, status_code=200)
return object_read(model_name, get, status_code=200)
def put_data(self, model_name=False, id=False, **post):
return object_update_one(
modelname=model_name,
id=id,
status_code=200,
)
def put_data(self, model_name=False, id=False, **put):
return object_update_one(model_name, id, put, status_code=200)
def post_data(self, model_name=False, id=False, **post):
return object_create_one(
modelname=model_name,
data={},
status_code=200,
)
def post_data(self, model_name=False, **post):
return object_create_one(model_name, post, status_code=200)
def delete_data(self, model_name=False, id=False):
return object_delete_one(
modelname=model_name,
id=id,
status_code=200
)
return object_delete_one(model_name, id, status_code=200)

View File

@ -11,11 +11,18 @@ except ImportError:
_logger = logging.getLogger(__name__)
class JSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, (bytes, bytearray)):
return obj.decode("utf-8")
return json.JSONEncoder.default(self, obj)
def valid_response(status, data):
return werkzeug.wrappers.Response(
status=status,
content_type='application/json; charset=utf-8',
response=json.dumps(data),
response=json.dumps(data, cls=JSONEncoder),
)
@ -39,35 +46,49 @@ def invalid_token():
_logger.error("Token is expired or invalid!")
return invalid_response(401, 'invalid_token', "Token is expired or invalid!")
def object_not_found():
def modal_not_found(modal_name):
_logger.error("Not found object(s) in flectra!")
return invalid_response(404, 'not_found_object_in_flectra',
"Not found object(s) in flectra!")
return invalid_response(404, 'object_not_found_in_flectra',
"Modal " + modal_name + " Not Found!")
def rest_api_unavailable(modal_name):
_logger.error("Not found object(s) in flectra!")
return invalid_response(404, 'object_not_found_in_flectra',
"Enable Rest API For " + modal_name + "!")
def object_not_found_all(modal_name):
_logger.error("Not found object(s) in flectra!")
return invalid_response(404, 'object_not_found_in_flectra',
"No Record found in " + modal_name + "!")
def object_not_found(record_id, modal_name):
_logger.error("Not found object(s) in flectra!")
return invalid_response(404, 'object_not_found_in_flectra',
"Record " + str(record_id) + " Not found in " + modal_name + "!")
def unable_delete():
_logger.error("Access Denied!")
return invalid_response(404, "you don't have access to delete records for "
return invalid_response(403, "you don't have access to delete records for "
"this model", "Access Denied!")
def no_object_created(flectra_error):
_logger.error("Not created object in flectra! ERROR: %s" % flectra_error)
return invalid_response(409, 'not_created_object_in_flectra',
return invalid_response(500, 'not_created_object_in_flectra',
"Not created object in flectra! ERROR: %s" %
flectra_error)
def no_object_updated(flectra_error):
_logger.error("Not updated object in flectra! ERROR: %s" % flectra_error)
return invalid_response(409, 'not_updated_object_in_flectra',
"Not updated object in flectra! ERROR: %s" %
return invalid_response(500, 'not_updated_object_in_flectra',
"Object Not Updated! ERROR: %s" %
flectra_error)
def no_object_deleted(flectra_error):
_logger.error("Not deleted object in flectra! ERROR: %s" % flectra_error)
return invalid_response(409, 'not_deleted_object_in_flectra',
return invalid_response(500, 'not_deleted_object_in_flectra',
"Not deleted object in flectra! ERROR: %s" %
flectra_error)

View File

@ -0,0 +1,315 @@
<section class="container">
<div class="row oe_spaced">
<h2 class="text-center">Guideline of Rest API</h2>
</div>
</section>
<section class="container oe_dark">
<div class="row oe_spaced">
<div class="col-md-12 bg-black">
<h3 class="text-center">Generate Token</h3>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
import requests
db_config = {
"username': "YOUR_EMAIL",
"password': "YOUR_PASSWORD",
"db': "SERVER_DATABASE_NAME"
}
server_url = "YOUR_SERVER_URL"
get_token_url = "/api/auth/get_tokens"
url = server_url + get_token_url
requests.post(url=url, data=db_config)
</code>
</div>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
<u><b>output:</b></u>
{
"company_id": 1,
"user_context": {
"lang": "en_US",
"tz": "Asia/Kolkata",
"uid": 1
},
"access_token": "YOUR_API_ACCESS_TOKEN",
"expires_in": "600",
"uid": 1
}
</code>
</div>
</div>
</div>
</section>
<section class="container oe_dark">
<div class="row oe_spaced">
<div class="col-md-12 bg-black">
<h3 class="text-center">Delete Token</h3>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
import requests
header = {
"access_token": "YOUR_API_ACCESS_TOKEN"
}
server_url = "YOUR_SERVER_URL"
del_token_url = "/api/auth/delete_tokens"
url = server_url + del_token_url
requests.post(url=url, headers=header)
</code>
</div>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
<u><b>output:</b></u>
{
"desc": "Token Successfully Deleted",
"delete": true
}
</code>
</div>
</div>
</div>
</section>
<section class="container oe_dark">
<div class="row oe_spaced">
<div class="col-md-12 bg-black">
<h3 class="text-center">POST Request</h3>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
import requests
header = {
"access_token": "YOUR_API_ACCESS_TOKEN"
}
data={
"name": "FlectraHQ",
"email": "example@flectrahq.com",
"website": "www.flectrahq.com"
}
server_url = "YOUR_SERVER_URL"
post_url = '/api/res.partner'
url = server_url + post_url
requests.post(url=url, data=data, headers=header)
</code>
</div>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
<u><b>output:</b></u>
{
"id": 300
}
</code>
</div>
</div>
</div>
</section>
<section class="container oe_dark">
<div class="row oe_spaced">
<div class="col-md-12 bg-black">
<h3 class="text-center">GET Request</h3>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
"""
"limit" : Integer eg. 10,
"field" : [List of Field(s) in String]
eg. "['name', 'email', ..]",
"order" : "String" eg. "name asc/desc",
"offset" : Integer eg. 3,
"filters" : [List of Condition(s) in String]
eg. "[('name', 'like', 'XXX'), ..]"
"""
import requests
header = {
"access_token": "YOUR_API_ACCESS_TOKEN"
}
data={
"limit": 3,
"field": "['name', 'email']",
"order": 'name desc'
}
server_url = "YOUR_SERVER_URL"
get_url = '/api/res.partner'
url = server_url + get_url
requests.get(url=url, data=data, headers=header)
</code>
</div>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
<u><b>output:</b></u>
{
"count": 3,
"results": [
{
"email": false,
"id": 44,
"name": "Your Company"
},
{
"email": "info@yourcompany.example.com",
"id": 1,
"name": "YourCompany"
},
{
"email": "william.jackson@jackson.example.com",
"id": 33,
"name": "William Thomas"
}
]
}
</code>
</div>
</div>
<div class="col-md-12 bg-black">
<h5 class="text-center">GET Request for Single Record</h5>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
"""
"field" : [List of Field(s) in String]
eg. "['name', 'email', ..]",
"""
import requests
header = {
"access_token": "YOUR_API_ACCESS_TOKEN"
}
data={
"field": "['name', 'email']",
}
server_url = "YOUR_SERVER_URL"
get_url = '/api/res.partner/1'
url = server_url + get_url
requests.get(url=url, data=data, headers=header)
</code>
</div>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
<u><b>output:</b></u>
[
{
"email": "info@yourcompany.example.com",
"name": "YourCompany",
"id": 1
}
]
</code>
</div>
</div>
</div>
</section>
<section class="container oe_dark">
<div class="row oe_spaced">
<div class="col-md-12 bg-black">
<h3 class="text-center">PUT Request</h3>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
import requests
header = {
"access_token": "YOUR_API_ACCESS_TOKEN"
}
data={
"name": "FlectraHQ",
"email": "example@flectrahq.com",
"website": "www.flectrahq.com"
"id": 300
}
server_url = "YOUR_SERVER_URL"
put_url = '/api/res.partner'
url = server_url + put_url
requests.put(url=url, data=data, headers=header)
</code>
</div>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
<u><b>output:</b></u>
{
"desc": "Record Updated successfully!",
"update": true
}
</code>
</div>
</div>
</div>
</section>
<section class="container oe_dark">
<div class="row oe_spaced">
<div class="col-md-12 bg-black">
<h3 class="text-center">DELETE Request</h3>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
import requests
header = {
"access_token": "YOUR_API_ACCESS_TOKEN"
}
data={
"id": 300
}
server_url = "YOUR_SERVER_URL"
put_url = '/api/res.partner'
url = server_url + put_url
requests.delete(url=url, data=data, headers=header)
</code>
</div>
<div class="col-md-6">
<code class="bg-black" style="white-space: pre-wrap;">
<u><b>output:</b></u>
{
"desc": "Record Successfully Deleted!",
"delete": true
}
</code>
</div>
</div>
</div>
</section>