def list_registered_resources(self, request): '''This method list all registered resources as well as a link to their entry point. .. code-block:: javascript // ROA api is mapped on a subdomain: roa.fantasticoproject.com // listing is done by GET http://fantasticoproject.com/roa/resources HTTP/1.1 { "Person": {1.0 : "http://roa.fantasticoproject.com/1.0/persons", "latest": "http://roa.fantasticoproject.com/latest/persons"}, "Address": {1.0 : "http://roa.fantasticoproject.com/1.0/addresses", 2.0 : "http://roa.fantasticoproject.com/2.0/addresses", "latest": "http://roa.fantasticoproject.com/latest/addresses"} } .. code-block:: javascript // ROA api is mapped on a relative path of the project: http://fantasticoproject.com/api/ // listing is done by GET http://fantasticoproject.com/roa/resources HTTP/1.1 { "Person": {1.0 : "http://fantasticoproject.com/api/1.0/persons", "latest": "http://roa.fantasticoproject.com/api/latest/persons"}, "Address": {1.0 : "http://roa.fantasticoproject.com/api/1.0/addresses", 2.0 : "http://roa.fantasticoproject.com/api/2.0/addresses", "latest": "http://roa.fantasticoproject.com/api/latest/addresses"} }''' body = {} resources = self._registry.all_resources() for resource in resources: if not body.get(resource.name): body[resource.name] = {} api_url = roa_helper.calculate_resource_url( self._roa_api, resource, resource.version) api_url_latest = roa_helper.calculate_resource_url( self._roa_api, resource, "latest") body[resource.name][resource.version] = api_url body[resource.name]["latest"] = api_url_latest body = json.dumps(body).encode() response = Response(body=body, content_type="application/json", charset="UTF-8") response.headers["Access-Control-Allow-Origin"] = "*" response.headers[ "Access-Control-Allow-Methods"] = "OPTIONS,GET,POST,PUT,DELETE" return response
def list_registered_resources(self, request): """This method list all registered resources as well as a link to their entry point. .. code-block:: javascript // ROA api is mapped on a subdomain: roa.fantasticoproject.com // listing is done by GET http://fantasticoproject.com/roa/resources HTTP/1.1 { "Person": {1.0 : "http://roa.fantasticoproject.com/1.0/persons", "latest": "http://roa.fantasticoproject.com/latest/persons"}, "Address": {1.0 : "http://roa.fantasticoproject.com/1.0/addresses", 2.0 : "http://roa.fantasticoproject.com/2.0/addresses", "latest": "http://roa.fantasticoproject.com/latest/addresses"} } .. code-block:: javascript // ROA api is mapped on a relative path of the project: http://fantasticoproject.com/api/ // listing is done by GET http://fantasticoproject.com/roa/resources HTTP/1.1 { "Person": {1.0 : "http://fantasticoproject.com/api/1.0/persons", "latest": "http://roa.fantasticoproject.com/api/latest/persons"}, "Address": {1.0 : "http://roa.fantasticoproject.com/api/1.0/addresses", 2.0 : "http://roa.fantasticoproject.com/api/2.0/addresses", "latest": "http://roa.fantasticoproject.com/api/latest/addresses"} }""" body = {} resources = self._registry.all_resources() for resource in resources: if not body.get(resource.name): body[resource.name] = {} api_url = roa_helper.calculate_resource_url(self._roa_api, resource, resource.version) api_url_latest = roa_helper.calculate_resource_url(self._roa_api, resource, "latest") body[resource.name][resource.version] = api_url body[resource.name]["latest"] = api_url_latest body = json.dumps(body).encode() response = Response(body=body, content_type="application/json", charset="UTF-8") response.headers["Access-Control-Allow-Origin"] = "*" response.headers["Access-Control-Allow-Methods"] = "OPTIONS,GET,POST,PUT,DELETE" return response
def create_item(self, request, version, resource_url): '''This method provides the route for adding new resources into an existing collection. The API is json only and invoke the validator as described in ROA spec. Usually, when a resource is created successfully a similar answer is returned to the client: .. code-block:: html 201 Created Content-Type: application/json Content-Length: 0 Location: /api/2.0/app-settings/123 Below you can find all error response codes which might be returned when creating a new resource: * **10000** - Whenever we try to create a resource with unknown type. (Not registered to ROA). * **10010** - Whenever we try to create a resource which fails validation. * **10020** - Whenever we try to create a resource without passing a valid body. * **10030** - Whenever we try to create a resource and an unexpected database exception occurs. You can find more information about typical REST ROA APIs response on :doc:`/features/roa/rest_responses`.''' if version != "latest": version = float(version) resource = self._resources_registry.find_by_url(resource_url, version) if not resource: return self._handle_resource_notfound(version, resource_url) model = self._validate_resource(resource, request, request.body) access_token = request.context.security.access_token if isinstance(model, Response): return model try: if resource.user_dependent and access_token: model.user_id = access_token.user_id if resource.validator: resource.validator().on_pre_create(model, request) model_facade = self._model_facade_cls(resource.model, self._get_current_connection(request)) model_id = model_facade.create(model)[0] if resource.validator: resource.validator().on_post_create(model, request) except FantasticoDbError as dbex: return self._handle_resource_dberror(resource.version, resource.url, dbex) model_location = roa_helper.calculate_resource_url(self._roa_api, resource, version) model_location += "/%s" % model_id response = Response(status_code=201, content_type="application/json") self._add_cors_headers(response) response.headers["Location"] = model_location return response
def test_calculate_resource_relative_api(self): '''This test case ensures an url is correctly built when roa_api is hosted on the same domain as the project.''' resource = Mock() resource.url = "/sample-resources" roa_api = "/api" self.assertEqual("/api/1.0%s" % resource.url, roa_helper.calculate_resource_url(roa_api, resource, 1.0))
def test_calculate_resource_abs_api(self): '''This test case ensures an url is correctly built when roa_api is hosted on a separate domain than the project.''' resource = Mock() resource.url = "/sample-resources" roa_api = "https://api.fantastico.com/roa/api" self.assertEqual("https://api.fantastico.com/roa/api/2.0%s" % resource.url, roa_helper.calculate_resource_url(roa_api, resource, 2.0))
def test_calculate_resource_abs_api(self): '''This test case ensures an url is correctly built when roa_api is hosted on a separate domain than the project.''' resource = Mock() resource.url = "/sample-resources" roa_api = "https://api.fantastico.com/roa/api" self.assertEqual( "https://api.fantastico.com/roa/api/2.0%s" % resource.url, roa_helper.calculate_resource_url(roa_api, resource, 2.0))
def test_calculate_resource_relative_api(self): '''This test case ensures an url is correctly built when roa_api is hosted on the same domain as the project.''' resource = Mock() resource.url = "/sample-resources" roa_api = "/api" self.assertEqual( "/api/1.0%s" % resource.url, roa_helper.calculate_resource_url(roa_api, resource, 1.0))
def create_item(self, request, version, resource_url): '''This method provides the route for adding new resources into an existing collection. The API is json only and invoke the validator as described in ROA spec. Usually, when a resource is created successfully a similar answer is returned to the client: .. code-block:: html 201 Created Content-Type: application/json Content-Length: 0 Location: /api/2.0/app-settings/123 Below you can find all error response codes which might be returned when creating a new resource: * **10000** - Whenever we try to create a resource with unknown type. (Not registered to ROA). * **10010** - Whenever we try to create a resource which fails validation. * **10020** - Whenever we try to create a resource without passing a valid body. * **10030** - Whenever we try to create a resource and an unexpected database exception occurs. You can find more information about typical REST ROA APIs response on :doc:`/features/roa/rest_responses`.''' if version != "latest": version = float(version) resource = self._resources_registry.find_by_url(resource_url, version) if not resource: return self._handle_resource_notfound(version, resource_url) model = self._validate_resource(resource, request, request.body) access_token = request.context.security.access_token if isinstance(model, Response): return model try: if resource.user_dependent and access_token: model.user_id = access_token.user_id if resource.validator: resource.validator().on_pre_create(model, request) model_facade = self._model_facade_cls( resource.model, self._get_current_connection(request)) model_id = model_facade.create(model)[0] if resource.validator: resource.validator().on_post_create(model, request) except FantasticoDbError as dbex: return self._handle_resource_dberror(resource.version, resource.url, dbex) model_location = roa_helper.calculate_resource_url( self._roa_api, resource, version) model_location += "/%s" % model_id response = Response(status_code=201, content_type="application/json") self._add_cors_headers(response) response.headers["Location"] = model_location return response