# Copyright 2018 ACSONE SA/NV # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). from functools import partial from graphql_server import ( HttpQueryError, encode_execution_results, format_error_default, json_encode, load_json_body, run_http_query, ) from odoo import http class GraphQLControllerMixin(object): def _parse_body(self): req = http.request.httprequest # We use mimetype here since we don't need the other # information provided by content_type content_type = req.mimetype if content_type == "application/graphql": return {"query": req.data.decode("utf8")} elif content_type == "application/json": return load_json_body(req.data.decode("utf8")) elif content_type in ( "application/x-www-form-urlencoded", "multipart/form-data", ): return http.request.params return {} def _process_request(self, schema, data): try: request = http.request.httprequest execution_results, all_params = run_http_query( schema, request.method.lower(), data, query_data=request.args, batch_enabled=False, catch=False, context_value={"env": http.request.env}, ) result, status_code = encode_execution_results( execution_results, is_batch=isinstance(data, list), format_error=format_error_default, encode=partial(json_encode, pretty=False), ) headers = dict() headers["Content-Type"] = "application/json" response = http.request.make_response(result, headers=headers) response.status_code = status_code if any(er.errors for er in execution_results): env = http.request.env env.cr.rollback() env.clear() return response except HttpQueryError as e: result = json_encode({"errors": [{"message": str(e)}]}) headers = dict(e.headers or {}) headers["Content-Type"] = "application/json" response = http.request.make_response(result, headers=headers) response.status_code = e.status_code env = http.request.env env.cr.rollback() env.clear() return response def _handle_graphql_request(self, schema): data = self._parse_body() return self._process_request(schema, data) def _handle_graphiql_request(self, schema): req = http.request.httprequest if req.method == "GET" and req.accept_mimetypes.accept_html: return http.request.render("graphql_base.graphiql", {}) # this way of passing a GraphQL query over http is not spec compliant # (https://graphql.org/learn/serving-over-http/), but we use # this only for our GraphiQL UI, and it works with Odoo's way # of passing the csrf token return self._process_request(schema, http.request.params)