method not allowed, when using onlyajax in controller action - ajax

Background:
I'm attempting to make good RESTful APIs in cakephp, and delegate front end work to a front end templating language Handlebars. As elicited here (http://www.dereuromark.de/2014/01/09/ajax-and-cakephp/) , using the JsonView and making an extensionful api is a good approach.
Problem:
Allowing only ajax by using $this->request->onlyAllow('ajax'); is returning method not allowed. I want to enforce this so my APIs are not directly called from the browser.
Could you (the community) validate my approach to building such APIs.
Code:
//At the controller
public function joinWithCode() {
//$this->request->onlyAllow('ajax'); //returns 405 method not allowed
//$this->request->onlyAllow('post'); //works and does not allow access from browser
$this->response->type('json');
$data = array(
'content' => 'something',
'error' => 'something else',
);
$this->set(compact('data'));
$this->set('_serialize', 'data');
}
//routes.php
Router::parseExtensions('json');
Router::connect('/Classrooms/join', array('controller' => 'classrooms', 'action' => 'joinWithCode'));
The post attempt from the postman extension:

Related

How can I validate GET controller params in CakePHP 2?

Given this on the model:
public $validate = [
'amount' => array(
'rule' => array('comparison', '>=', 0),
'message' => 'You must buy over 0 of this item!'
)
];
How can I validate param #2 of the below?
public function buy(int $item, int $amount) {
Validation seems to be built only for POST, which I'd like to opt out of here.
First things first, modifying the database with GET requests is an anti-pattern for many different reasons. Even if you assume a friendly user agent (which you never should!), browsers can behave quirky and do unexpected stuff like for example sending GET request multiple times (that is perfectly valid as GET is not ment to modify data), which they usually won't for POST/PUT/DELETE.
I would strongly suggest to change your endpoint to handle POST requests instead.
That being said, you can generally validate whatever you want, the validation mechanisms first and foremost just validate data, they don't know or care where it stems from. You can hand over whatever data you want to your model, and let it validate it:
$data = array(
'item' => $item,
'amount' => $amount,
);
$this->ModelName->set($data);
if ($this->ModelName->validates()) {
// data is valid
} else {
// data is invalid
$errors = $this->ModelName->validationErrors;
}
Moreover you can use CakePHP's validation methods completely manually too:
App::uses('Utility', 'Validation');
$isValid = Validation::comparison($amount, '>' 0);
This example of course doesn't make too much sense, given that $isValid = $amount > 0 would do the same, however it should just show that you can validate anything everywhere without models being involved.
See also
Cookbook > Models > Data Validation > Validating Data from the Controller
Cookbook > Models > Data Validation > Core Validation Rules

Can't access request data in production but can in local env

I'm working with a legacy Cakephp 2 app and need to create users via AJAX post on another domain.
I've got the whole thing working nicely in my local environment but have been battling with my prod environment.
I am using Postman to form a consistent Post request and setting the various headers as well as setting data values.
Locally:
I send a post request to a URL and var_dump the entire request object into the response. I can see that my data is populated. $this->request->data['email'] returns exactly what I expect.
Production:
I deploy the exact same code and my data array is completely empty.
I have set my Access-Control-Allow headers and I'm not getting any authisation issues. I can interact with the request within the application but I can not access any data. The request is the same request just a different endpoint.
I am running identical versions of PHP and exactly the same codebase.
Can anyone think of any environmental factors that might affect the request data?
This is my controller code in brief:
public function remoteadd() {
var_dump($this->request);
if ($this->request->is('ajax')) {
$this->disableCache();
$this->autoRender = false;
$this->response->type('json');
$this->User->create();
$gen_pass = $this->generatePassword();
$this->request->data['password'] = $gen_pass;
$emailAddr = $this->request->data['email'];
// Check if this email exists
$conditions = array(
'User.email' => $emailAddr,
);
if (!$this->User->hasAny($conditions)) {
if ($this->User->save($this->request->data)) {
$this->response->statusCode(200);
$this->response->body(json_encode(
array('status' => 'success', 'message' => 'New account successfully created')
));
}
} else {
$this->response->statusCode(500);
$this->response->body(json_encode(
array('status' => 'error', 'message' => 'Email address already exists')
));
}
$this->response->send();
$this->_stop();
}
}
It seems like the issue related to CORS preflight. Two requests are actually triggered. The first is a preflight which given my controller action is not returning any data as it's not actually a legitimate post request. The second request/response has the data appropriately loaded as expected.

How can I Implement Zend Framework 3 + Ajax Pagination?

Does anyone know how to implement Ajax Pagination with Zend Framework 3 (zf3)?
I used Doctrine ORM to retrieve data from database.
Sure. The same as a normal GET request really, only will you respond dynamically because it concerns an xml http request.
Take, for example, the following indexAction
use Zend\View\Model\JsonModel;
// class, other use-statements, etc
public function indexAction()
{
$page = $this->params()->fromQuery('page', 1); // get page from GET, default page 1
/** #var QueryBuilder $qb */
$qb = $this->getObjectManager()->createQueryBuilder();
$qb->select('u')
->from(User::class, 'u')
->orderBy('u.createdAt', 'DESC');
$paginator = new Paginator(new OrmAdapter(new OrmPaginator($qb)));
$paginator->setCurrentPageNumber($page);
$paginator->setItemCountPerPage(25);
if ($this->getRequest()->isXmlHttpRequest()) {
return new JsonModel([
'paginator' => $paginator,
'queryParams' => $this->params()->fromQuery(),
]);
}
return [
'paginator' => $paginator,
'queryParams' => $this->params()->fromQuery(),
];
}
Here you would normally end up at the bottom most return statement for a standard GET request. In case of an ajax type request, the statement $this->getRequest()->isXmlHttpRequest() returns true and you know it's something send via, let's say $.ajax / $.get / $.post (usually, unless native JS or something similar). In these cases you want to respond with just the data, not a completely rendered views. This is when you return the JsonModel.
To make sure it works as intended, you must also have the JsonViewStrategy enabled in your configuration. You might wish to enable this in your global.php instead of just a module, like below, to enable it everywhere:
'view_manager' => [
//...
'strategies' => [
'ViewJsonStrategy',
],
],
The only things left to do, then, are client-side things with JavaScript. Like making sure you update the pagination, page contents, etc. Maybe a URI anchor...

Http request and response in codeigniter

I am currently working in codeigniter and I am new to this.
I was wondering how to retrieve the JSON values using API call .
Can anyone suggest me where should I start.
Many Thanks in advance
Pass your array of row to json_encode();example for method of controller is below
public function getUserList() {
header('Content-Type: application/json');
$query = $this->db->get('mytable');
if(count($query) > 0) {
$message = array('status' => 'true' , 'message' => 'Record get successfully' , 'data' => $return );
}else{
$message = array('status' => 'false' , 'message' => 'Record not found.' );
}
echo json_encode($message);
}
Codeigniter does not have an inbuilt HTTP method so you need to use other things in php to achieve this.
There are 2 ways, you can use cURL, but honestly... it's convoluted... but read this: http://php.net/manual/en/book.curl.php
Another method is using stream_context_create() http://php.net/manual/en/function.stream-context-create.php
I strongly suggest using this 2nd one as its much easier to work with (in context with curl..
Much of how you setup your request depends on the API you are referencing with and the kind of requests it allows: GET, POST ... and what kind of header information it requires you to send over as well do they require oAuth header?
There is no 1 bunch of code fits all, I had to create a full custom library to integrate codeigniter into Magento, it took many hours.

Perl Dancer Testing: No route_exists for ajax routes?

I use the use Dancer::Plugin::Ajax to define some ajax routes in perl Dancer.
get '/' => sub {
template 'index' => $data;
};
ajax '/api/foo' => sub {
...
};
ajax '/api/bar' => sub {
...
};
In my test I would like to test if all the routes do exist:
route_exists [GET => '/'], 'a route handler is defined for /';
route_exists [AJAX => '/api/foo'], 'an ajax route handler is defined for /api/foo';
route_exists [AJAX => '/api/bar'], 'an ajax route handler is defined for /api/bar';
But unfortunately that does not work. I also tried
route_exists [GET => '/api/foo'], 'an ajax route handler is defined for /api/foo';
route_exists [GET => '/api/bar'], 'an ajax route handler is defined for /api/bar';
without succes.
Did I miss the right statement in the documentation?
Update after the first answer from #simbabque:
It nearly works now.
Unfortunatly find_route in Dancer::App uses
next if $r->has_options && (not $r->validate_options($request));
if it would use
next if $r->has_options && (not $r->check_options($request));
everything would work fine.
Background is: validate_options in Dancer::Route only checks the $_options_aliases, but the
required option is 'ajax' and that is only mentioned in $_supported_options.
Ideas how to work around this limitation?
(I will add my solution if this is fixed.)
This is not a complete answer, just a collection of stuff that will help you figure it out.
First, look at https://metacpan.org/source/YANICK/Dancer-1.3121/lib/Dancer/Request.pm#L341. The is_ajax method checks if the request has $self->{x_requested_with} eq "XMLHttpRequest".
If you look at https://metacpan.org/source/YANICK/Dancer-1.3121/t/15_plugins/07_ajax_plack_builder.t, which is the test for the Ajax plugin, it will create a fresh HTTP::Request.
My guess is you will need to do that too, in some way. Look at https://metacpan.org/source/YANICK/Dancer-1.3121/lib/Dancer/Test.pm#L107 for route_exists and hack your own version of that for ajax requests.
Update:
I hacked a little but did not test this at all:
*Dancer::Test::ajax_route_exists = sub {
my ($req, $test_name) = #_;
my $tb = Test::Builder->new;
my ($method, $path) = expand_req($req);
$test_name ||= "a route exists for $method $path";
$req = Dancer::Request->new_for_request($method => $path, undef, undef, HTTP::Headers->new( 'X-Requested-With' => 'XMLHttpRequest'));
return $tb->ok(defined(Dancer::App->find_route_through_apps($req)), $test_name);
}
Might be this works afterwards:
Dancer::Test::ajax_route_exists [GET => '/api/foo'], 'an ajax route handler is defined for /api/foo';

Resources