0

I have successfully created a new endpoint/route and can view it via wp-json. Not only that, I can successfully make a post request to this endpoint externally from the browser using the Restlet Client. My endpoint handles json within the body of the request, transforms and edits the data, then makes an external api call, then sends new data back to the client from the external api.

However, when I run an application on my wordpress site that calls this api, I get 400 Bad Request. I handle errors in many places within my function, and send back specific error messages based on types of errors that can occur in the data and I can't seem to find where this is coming from. I have set WP_DEBUG to true, and I'm stuck.

I think it may have to do with handling the pre-flight request but not sure.

Can you help me find the error?

PreFlight Handling

function handle_preflight() {
    header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); //HTTP 1.1
    header("Pragma: no-cache"); //HTTP 1.0
    header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
    header("Access-Control-Allow-Origin: *"); // change * to the known origin once this is put into place
    header("Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS");
    header("Access-Control-Allow-Headers: Content-Type");
    header('Access-Control-Max-Age: 50');
    header("Content-Type: application/json");

    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        header("Access-Control-Allow-Headers: X-Requested-With, Content-Type");
        http_response_code(200);
        exit();
    }
}

add_action( 'init', 'handle_preflight' );

Init REST endpoint

add_action( 'rest_api_init', function() {
    $version = '1';
    $namespace = "cbngiving/v".$version;
    $base = "giving";
    register_rest_route( $namespace, "/" . $base, array(
        'methods' => 'POST, OPTIONS',
        'callback'=> 'proxy_data'
    ));
});

CALLBACK

function proxy_data($request) {
    $data = $request->get_json_params();
    if(is_null($data)) {
        $response = new WP_REST_Response(array('statusText' => "Bad Request - Your request is missing parameters. Please verify and resubmit.",
        "origin" => "Bad Request from App to Proxy"));
        $response->set_status(400);
        return $response;
    } else {
        $mode = $data['mode'];
        $data['APIAccessID'] = ''; // to be added later
        $data['UrlReferrer'] = $_SERVER["HTTP_REFERRER"];
        $data['ClientBrowser'] = $_SERVER["HTTP_USER_AGENT"];
        $service_url_local = "PRIVATE ENDPOINT< NOT CAUSING ERROR!";
        $service_url_secure = "PRIVATE ENDPOINT< NOT CAUSING ERROR!";
        $service_url = $mode === "production" ? $service_url_secure : $service_url_local;
        unset($data['mode']);
        $proxy_response = wp_remote_post($service_url, array(
            'headers' => array(                                                                          
                'Content-Type' => 'application/json; charset=utf-8',
                'Accept' => 'application/json; charset=utf-8'
            ),
            'body' => json_encode($data)
        ));
        $proxy_response_code = wp_remote_retrieve_response_code( $proxy_response );
        $proxy_response_body = wp_remote_retrieve_body( $proxy_response );
        if ($proxy_response_code >=200 and $proxy_response_code < 300) {
            $response = new WP_REST_Response($proxy_response_body);
            $response->set_status(201);
            return $response;
        } else {
            $error = json_decode($proxy_response_body, TRUE);
            $response = new WP_REST_Response(array("statusText" => $error, "origin" => "Error Response from Giving Services"));
            $response->set_status($proxy_response_code);
            return $response;
        }
    }
}

UPDATED TO INCLUDE API CALL FROM REACT APPLICATION

I'm using the Fetch Api within a React Application that is being added to the page via a script.

fetch(proxy, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
})
.then(checkStatus)
.then(parseJSON)
.then(json=>{
    const msg = json;
    self.props.submitForm({msg, data})
}).catch(error=>{
    logError({error});
    this.setState({submitting: false})
});

HELPER FUNCTIONS

function logError({error}) {
    console.error(JSON.stringify(error, null, 5))
    if (error.status >= 500) {
        alert('There was an internal error submitting your form. Please check your information and try again or call us at PRIVATE');
    }
}

function checkStatus(response) {
    console.log({response})
    if (response.status >= 200 && response.status < 300) {
        return response
    } else {
        var error = new Error(response.statusText)
        error.response = response
        error.status = response.status
        throw error
    }
}

function parseJSON(response) {
    return response.json()
}
  • What happens when you disable the handle_preflight() (comment out the add_action())? Does the 400 error persist? – Sally CJ Sep 27 '18 at 5:29
  • @SallyCJ Yes. It persists. – wlh Sep 27 '18 at 12:49
  • Then it shouldn't be a pre-flight issue. Perhaps the request body was empty or not a valid JSON string? See the is_null($data) in the proxy_data() function. Try temporarily change the $response->set_status(400); to $response->set_status(200); (or use another status other than 400).. and see if you get the 200 status. If yes, then the problem was probably with the request body. – Sally CJ Sep 27 '18 at 13:13
  • That's not the issue either. I tried what you said, same response, but I could also tell that from the lack of the full error (statusText, origin) in the logged error. The errors I define within my function include extra information so that I know the error is generated by a particular issue with the submitted data. Even so, I changed the 400 to 200 and still got the 400 error. – wlh Sep 27 '18 at 13:34
  • 1
    Just found my problem. – wlh Sep 27 '18 at 14:09
1

There were three problems I discovered with my code above.

First, $_SERVER["HTTP_REFERRER"]; is an undefined index, moreover it is mispelled - HTTP_REFERER would be correct if it could be accessed this way in WP. I found get_http_origin() instead.

$data['UrlReferer'] = get_http_origin();

Second, I also mispelled the field I was saving this variable to - UrlReferrer (bad), UrlReferer (correct), something only I could have detected by testing on my end. But I wouldn't have caught this if I didn't catch the first.

Third, I dropped $data['ClientBrowser'] = $_SERVER["HTTP_USER_AGENT"]; since I can get that client side.

UPDATE

I can also get the URL referrer from the client side as well, by passing window.location.href to the api.

  • +1 :). PHP should make HTTP_REFERER and HTTP_REFERRER work interchangably! XD – Sally CJ Sep 28 '18 at 0:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.