Exemple #1
0
        async def handle_http_query(
            request: Request,
            response: Response,
            context=Depends(self.context_getter),
            root_value=Depends(self.root_value_getter),
        ) -> Response:
            actual_response: Response

            content_type = request.headers.get("content-type", "")

            if "application/json" in content_type:
                try:
                    data = await request.json()
                except json.JSONDecodeError:
                    actual_response = PlainTextResponse(
                        "Unable to parse request body as JSON",
                        status_code=status.HTTP_400_BAD_REQUEST,
                    )

                    return self._merge_responses(response, actual_response)
            elif content_type.startswith("multipart/form-data"):
                multipart_data = await request.form()
                operations = json.loads(multipart_data.get("operations", {}))
                files_map = json.loads(multipart_data.get("map", {}))
                data = replace_placeholders_with_files(
                    operations, files_map, multipart_data
                )
            else:
                actual_response = PlainTextResponse(
                    "Unsupported Media Type",
                    status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
                )

                return self._merge_responses(response, actual_response)

            try:
                request_data = parse_request_data(data)
            except MissingQueryError:
                actual_response = PlainTextResponse(
                    "No GraphQL query found in the request",
                    status_code=status.HTTP_400_BAD_REQUEST,
                )
                return self._merge_responses(response, actual_response)

            result = await self.execute(
                request_data.query,
                variables=request_data.variables,
                context=context,
                operation_name=request_data.operation_name,
                root_value=root_value,
            )

            response_data = await self.process_result(request, result)

            actual_response = JSONResponse(
                response_data,
                status_code=status.HTTP_200_OK,
            )

            return self._merge_responses(response, actual_response)
Exemple #2
0
def test_empty_operations_paths():
    operations = {
        "query": "mutation($files: [Upload!]!) { upload_files(files: $files) { id } }",
        "variables": {"files": [None, None]},
    }
    files_map = {"0": [], "1": []}
    files = {"0": BytesIO(), "1": BytesIO()}

    result = replace_placeholders_with_files(operations, files_map, files)
    assert result == operations
Exemple #3
0
 def parse_body(self, request: Request) -> dict:
     if request.content_type.startswith("multipart/form-data"):
         files = convert_request_to_files_dict(request)
         operations = json.loads(request.form.get("operations", "{}"))
         files_map = json.loads(request.form.get("map", "{}"))
         try:
             return replace_placeholders_with_files(operations, files_map,
                                                    files)
         except KeyError:
             abort(400, "File(s) missing in form data")
     return request.json
Exemple #4
0
    def parse_body(self, request) -> Dict[str, Any]:
        if request.content_type.startswith("multipart/form-data"):
            data = json.loads(request.POST.get("operations", "{}"))
            files_map = json.loads(request.POST.get("map", "{}"))

            data = replace_placeholders_with_files(data, files_map,
                                                   request.FILES)

            return data

        return json.loads(request.body)
Exemple #5
0
def test_does_deep_copy():
    operations = {
        "query": "mutation($file: Upload!) { upload_file(file: $file) { id } }",
        "variables": {"file": None},
    }
    files_map = {}
    files = {}

    result = replace_placeholders_with_files(operations, files_map, files)
    assert result == operations
    assert result is not operations
Exemple #6
0
def test_single_file_in_single_location():
    operations = {
        "query": "mutation($file: Upload!) { upload_file(file: $file) { id } }",
        "variables": {"file": None},
    }
    files_map = {"0": ["variables.file"]}
    file0 = BytesIO()
    files = {"0": file0}

    result = replace_placeholders_with_files(operations, files_map, files)
    assert result["query"] == operations["query"]
    assert result["variables"]["file"] == file0
Exemple #7
0
def test_single_file_in_multiple_locations():
    operations = {
        "query": "mutation($a: Upload!, $b: Upload!) { pair(a: $a, b: $a) { id } }",
        "variables": {"a": None, "b": None},
    }
    files_map = {"0": ["variables.a", "variables.b"]}
    file0 = BytesIO()
    files = {"0": file0}

    result = replace_placeholders_with_files(operations, files_map, files)
    assert result["query"] == operations["query"]
    assert result["variables"]["a"] == file0
    assert result["variables"]["b"] == file0
Exemple #8
0
def test_using_single_file_multiple_times_in_same_list():
    operations = {
        "query": "mutation($files: [Upload!]!) { upload_files(files: $files) { id } }",
        "variables": {"files": [None, None]},
    }
    files_map = {"0": ["variables.files.0", "variables.files.1"]}
    file0 = BytesIO()
    files = {"0": file0}

    result = replace_placeholders_with_files(operations, files_map, files)
    assert result["query"] == operations["query"]
    assert result["variables"]["files"][0] == file0
    assert result["variables"]["files"][1] == file0
Exemple #9
0
def test_deep_nesting():
    operations = {
        "query": "mutation($list: [ComplexInput!]!) { mutate(list: $list) { id } }",
        "variables": {"a": [{"files": [None, None]}]},
    }
    files_map = {"0": ["variables.a.0.files.0"], "1": ["variables.a.0.files.1"]}
    file0 = BytesIO()
    file1 = BytesIO()
    files = {"0": file0, "1": file1}

    result = replace_placeholders_with_files(operations, files_map, files)
    assert result["query"] == operations["query"]
    assert result["variables"]["a"][0]["files"][0] == file0
    assert result["variables"]["a"][0]["files"][1] == file1
Exemple #10
0
def test_single_file_reuse_in_list():
    operations = {
        "query": "mutation($a: [Upload!]!, $b: Upload!) { mixed(a: $a, b: $b) { id } }",
        "variables": {"a": [None, None], "b": None},
    }
    files_map = {"0": ["variables.a.0"], "1": ["variables.a.1", "variables.b"]}
    file0 = BytesIO()
    file1 = BytesIO()
    files = {"0": file0, "1": file1}

    result = replace_placeholders_with_files(operations, files_map, files)
    assert result["query"] == operations["query"]
    assert result["variables"]["a"][0] == file0
    assert result["variables"]["a"][1] == file1
    assert result["variables"]["b"] == file1
Exemple #11
0
    def dispatch_request(self):
        if "text/html" in request.environ.get("HTTP_ACCEPT", ""):
            if not self.graphiql:
                abort(404)

            template = render_graphiql_page()
            return self.render_template(template=template)

        if request.content_type.startswith("multipart/form-data"):
            operations = json.loads(request.form.get("operations", "{}"))
            files_map = json.loads(request.form.get("map", "{}"))

            data = replace_placeholders_with_files(operations, files_map,
                                                   request.files)

        else:
            data = request.json

        try:
            request_data = parse_request_data(data)
        except MissingQueryError:
            return Response("No valid query was provided for the request", 400)

        context = self.get_context()

        result = self.schema.execute_sync(
            request_data.query,
            variable_values=request_data.variables,
            context_value=context,
            operation_name=request_data.operation_name,
            root_value=self.get_root_value(),
        )

        response_data = self.process_result(result)

        return Response(
            json.dumps(response_data),
            status=200,
            content_type="application/json",
        )
Exemple #12
0
    async def parse_multipart_body(self, request: web.Request) -> dict:
        reader = await request.multipart()
        operations: Dict[str, Any] = {}
        files_map: Dict[str, Any] = {}
        files: Dict[str, Any] = {}
        try:
            async for field in reader:
                if field.name == "operations":
                    operations = (await field.json()) or {}
                elif field.name == "map":
                    files_map = (await field.json()) or {}
                elif field.filename:
                    assert field.name

                    files[field.name] = BytesIO(await field.read(decode=False))
        except ValueError:
            raise web.HTTPBadRequest(
                reason="Unable to parse the multipart body")
        try:
            return replace_placeholders_with_files(operations, files_map,
                                                   files)
        except KeyError:
            raise web.HTTPBadRequest(reason="File(s) missing in form data")
Exemple #13
0
    async def get_http_response(
        self,
        request: Request,
        execute: Callable,
        process_result: Callable,
        graphiql: bool,
        root_value: Optional[Any],
        context: Optional[Any],
    ) -> Response:
        if request.method == "GET":
            if not graphiql:
                return HTMLResponse(status_code=status.HTTP_404_NOT_FOUND)

            return self.get_graphiql_response()

        if request.method == "POST":
            content_type = request.headers.get("Content-Type", "")
            if "application/json" in content_type:
                try:
                    data = await request.json()
                except json.JSONDecodeError:
                    return PlainTextResponse(
                        "Unable to parse request body as JSON",
                        status_code=status.HTTP_400_BAD_REQUEST,
                    )
            elif content_type.startswith("multipart/form-data"):
                multipart_data = await request.form()
                operations = json.loads(multipart_data.get("operations", "{}"))
                files_map = json.loads(multipart_data.get("map", "{}"))

                data = replace_placeholders_with_files(
                    operations, files_map, multipart_data
                )

            else:
                return PlainTextResponse(
                    "Unsupported Media Type",
                    status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
                )
        else:
            return PlainTextResponse(
                "Method Not Allowed",
                status_code=status.HTTP_405_METHOD_NOT_ALLOWED,
            )

        try:
            request_data = parse_request_data(data)
        except MissingQueryError:
            return PlainTextResponse(
                "No GraphQL query found in the request",
                status_code=status.HTTP_400_BAD_REQUEST,
            )

        result = await execute(
            request_data.query,
            variables=request_data.variables,
            context=context,
            operation_name=request_data.operation_name,
            root_value=root_value,
        )

        response_data = await process_result(request=request, result=result)

        return JSONResponse(response_data, status_code=status.HTTP_200_OK)