diff --git a/example/app/main.py b/example/app/main.py index 16a6569..ae19481 100644 --- a/example/app/main.py +++ b/example/app/main.py @@ -115,6 +115,7 @@ def most_similar(query_results, ctx, part, eval_part): cors_enabled=True, example_query=example_query, example_queries=example_queries, + enable_update=True, ) ## Uncomment to run it directly with python app/main.py diff --git a/src/rdflib_endpoint/sparql_router.py b/src/rdflib_endpoint/sparql_router.py index 89c2ce1..427c52b 100644 --- a/src/rdflib_endpoint/sparql_router.py +++ b/src/rdflib_endpoint/sparql_router.py @@ -115,9 +115,7 @@ def _parse_preference(qpref: str) -> float: qparts = qpref.split("=") try: return float(qparts[1].strip()) - except ValueError: - pass - except IndexError: + except (ValueError, IndexError): pass return 1.0 @@ -197,22 +195,10 @@ def __init__( elif len(self.functions) > 0: rdflib.plugins.sparql.CUSTOM_EVALS["evalCustomFunctions"] = self.eval_custom_functions - # TODO: use add_api_route? https://github.com/tiangolo/fastapi/blob/d666ccb62216e45ca78643b52c235ba0d2c53986/fastapi/routing.py#L548 - @self.get( - self.path, - name="SPARQL endpoint", - description=self.example_markdown, - responses=api_responses, - ) - async def sparql_endpoint( - request: Request, query: Optional[str] = Query(None), update: Optional[str] = None # Not supported for GET + async def handle_sparql_request( + request: Request, query: Optional[str] = None, update: Optional[str] = None ) -> Response: - """ - Send a SPARQL query to be executed through HTTP GET operation. - - :param request: The HTTP GET request - :param query: SPARQL query input. - """ + """Handle SPARQL requests to the GET and POST endpoints""" if query and update: return JSONResponse( status_code=400, @@ -295,7 +281,7 @@ async def sparql_endpoint( status_code=400, content={"message": "Error executing the SPARQL query on the RDFLib Graph"}, ) - else: # update + else: # Update if not self.enable_update: return JSONResponse( status_code=403, content={"message": "INSERT and DELETE queries are not allowed."} @@ -319,6 +305,25 @@ async def sparql_endpoint( content={"message": "Error executing the SPARQL update on the RDFLib Graph"}, ) + # TODO: use add_api_route? https://github.com/tiangolo/fastapi/blob/d666ccb62216e45ca78643b52c235ba0d2c53986/fastapi/routing.py#L548 + @self.get( + self.path, + name="SPARQL endpoint", + description=self.example_markdown, + responses=api_responses, + ) + async def get_sparql_endpoint( + request: Request, + query: Optional[str] = Query(None), + ) -> Response: + """ + Send a SPARQL query to be executed through HTTP GET operation. + + :param request: The HTTP GET request + :param query: SPARQL query input. + """ + return await handle_sparql_request(request, query=query) + @self.post( path, name="SPARQL endpoint", @@ -345,11 +350,13 @@ async def post_sparql_endpoint(request: Request) -> Response: query = parse.unquote(query_params[0]) if query_params else None update_params = [kvp[1] for kvp in request_params if kvp[0] == "update"] update = parse.unquote(update_params[0]) if update_params else None + # TODO: handle params `using-graph-uri` and `using-named-graph-uri` + # https://www.w3.org/TR/sparql11-protocol/#update-operation else: # Response with the service description query = None update = None - return await sparql_endpoint(request, query, update) + return await handle_sparql_request(request, query, update) def eval_custom_functions(self, ctx: QueryContext, part: CompValue) -> List[Any]: """Retrieve variables from a SPARQL-query, then execute registered SPARQL functions diff --git a/tests/test_parse_accept.py b/tests/test_parse_accept.py index c37d7c8..73e06a4 100644 --- a/tests/test_parse_accept.py +++ b/tests/test_parse_accept.py @@ -6,6 +6,7 @@ ("text/xml", "text/xml"), ("text/rdf+xml, text/xml, */*", "text/rdf+xml"), ("text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8", "text/html"), + ("text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=", "text/html"), ("text/html;q=0.3, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8", "application/xhtml+xml"), ( 'text/turtle;q=0.9;profile="urn:example:profile-1", text/turtle;q=0.7;profile="urn:example:profile-2"', diff --git a/tests/test_rdflib_endpoint.py b/tests/test_rdflib_endpoint.py index db5dafa..7f5cf8d 100644 --- a/tests/test_rdflib_endpoint.py +++ b/tests/test_rdflib_endpoint.py @@ -112,6 +112,11 @@ def test_sparql_update(api_key, key_provided, param_method, monkeypatch): assert (subject, RDFS.label, Literal("bar")) not in graph +def test_sparql_query_update_fail(): + response = endpoint.post("/", data={"update": label_patch, "query": label_patch}) + assert response.status_code == 400 + + def test_multiple_accept_return_json(): response = endpoint.get( "/",