public function request($type, $file = null)
    {
        static $retries = [];

        // check if not checked
        $this->check();

        // check if is cached
        if(isset($this->cache[sha1($file)][$type]))
        {
            return $this->cache[sha1($file)][$type];
        }
        elseif(!isset($retries[sha1($file)]))
        {
            $retries[sha1($file)] = $this->retries;
        }

        // parameters for cURL request
        list($resource, $headers) = $this->getParameters($type, $file);

        // check the request
        $file = parent::checkRequest($type, $file);

        // cURL options
        $options = $this->getCurlOptions($type, $file);

        // sets headers
        foreach($headers as $header)
        {
            $options[CURLOPT_HTTPHEADER][] = $header;
        }

        // cURL init and options
        $options[CURLOPT_URL] = $this->getUrl() . "/$resource";

        // get the response and the HTTP status code
        list($response, $status) = $this->exec($options);

        // reduce memory usage closing cURL resource
        if(isset($options[CURLOPT_INFILE]) && is_resource($options[CURLOPT_INFILE]))
        {
            fclose($options[CURLOPT_INFILE]);
        }

        // request completed successfully
        if($status == 200)
        {
            if($type == 'meta')
            {
                $response = Metadata::make($response, $file);
            }

            // cache certain responses
            if(in_array($type, ['lang', 'meta']))
            {
                $this->cache[sha1($file)][$type] = $response;
            }
        }
        // request completed successfully but result is empty
        elseif($status == 204)
        {
            $response = null;
        }
        // retry on request failed with error 500
        elseif($status == 500 && $retries[sha1($file)]--)
        {
            $response = $this->request($type, $file);
        }
        // other status code is an error
        else
        {
            $this->error($status, $resource);
        }

        return $response;
    }