def _request(self, req_and_resp, **kwargs):
        """ Take a request_and_response object from pyswagger.App and
        check auth, token, headers, prepare the actual request and fill the
        response

        Note on performance : if you need more performance (because you are
        using this in a batch) you'd rather set raw_body_only=True, as parsed
        body is really slow. You'll then have to get data from response.raw
        and convert it to json using "json.loads(response.raw)"

        :param req_and_resp: the request and response object from pyswagger.App
        :param raw_body_only: define if we want the body to be parsed as object
                              instead of staying a raw dict. [Default: False]
        :param opt: options, see pyswagger/blob/master/pyswagger/io.py#L144
        :param raise_on_error: boolean to raise an error if HTTP Code >= 400

        :return: the final response.
        """

        opt = kwargs.pop('opt', {})

        # reset the request and response to reuse existing req_and_resp
        req_and_resp[0].reset()
        req_and_resp[1].reset()

        # required because of inheritance
        request, response = super(EsiClient, self).request(req_and_resp, opt)

        # check cache here so we have all headers, formed url and params
        cache_key = make_cache_key(request)
        res = self.__make_request(request, opt, cache_key)

        if res.status_code == 200:
            self.__cache_response(cache_key, res, request.method.upper())

        # generate the Response object from requests response
        response.raw_body_only = kwargs.pop(
            'raw_body_only',
            self.raw_body_only
        )

        try:
            response.apply_with(
                status=res.status_code,
                header=res.headers,
                raw=six.BytesIO(res.content).getvalue()
            )

        except ValueError:
            # catch JSONDecodeError/ValueError when response is not JSON
            raise APIException(
                request.url,
                res.status_code,
                response=res.content,
                request_param=request.query,
                response_header=res.headers
            )

        if 'warning' in res.headers:
            # send in logger and warnings, so the user doesn't have to use
            # logging to see it (at least once)
            LOGGER.warning("[%s] %s", res.url, res.headers['warning'])
            warnings.warn("[%s] %s" % (res.url, res.headers['warning']))

        if res.status_code >= 400 and kwargs.pop('raise_on_error', False):
            raise APIException(
                request.url,
                res.status_code,
                response=response.raw,
                request_param=request.query,
                response_header=response.header
            )

        return response