I am creating rest api for symfony 2,but not able to pass JSON data to post method. $userform->isValid()always failed.
curl -v -H "Accept: application/json" -X POST -d '{"username":"hitesh","userpassword":"hitesh123"}' http://localhost/us/serenify/web/app_dev.php/user/login
This is the data I am passing for test purpose.
public function loginAction(Request $request)
{
return $this->processForm(new User(),$request);
}
private function processForm(User $user,$request)
{
$userform = $this->createForm(new UserType(), $user);
$content = $this->getRequest();
$userform->submit($content);
$key = md5(microtime().rand());
if ($userform->isValid())
{
if(trim($data['username'])=="" || trim($data['userpassword']==""))
{
$data=array(
"success"=>'false',
"msg"=>'username or password is blank'
);
$response = new Response(json_encode($data));
$response->setStatusCode(203);
$response->headers->set('Content-Type', 'application/json');
}
else
{
$username=trim($data['username']);
$userpassword=trim(md5($data['userpassword']));
$user = $this->getDoctrine()
->getRepository('SerenifyUserBundle:User')
->findOneBy(array('username' => $username, 'userpassword' => $userpassword));
if (!$user)
{
$data=array(
"success"=>'false',
"msg"=>'username or password is wrong'
);
$response = new Response(json_encode($data));
$response->setStatusCode(404);
$response->headers->set('Content-Type', 'application/json');
}
else
{
$data=array(
"success"=>'true',
"msg"=>'user has sucessfully logged in',
"username" => $username,
"sessionis" => $key,
);
$response = new Response(json_encode($data));
$response->setStatusCode(404);
$response->headers->set('Content-Type', 'application/json');
}
$response = new Response(json_encode($data));
}
}
else
{
$data=array(
"success"=>'false',
"msg"=>'invalid form content'
);
$response = new Response(json_encode($data));
$response->setStatusCode(404);
$response->headers->set('Content-Type', 'application/json');
}
return $response;
}
Above is my controller code.
When I print request value is does not show in JSON format.
Anyway to test or pass JSON data? I am creating login functionality.
FOSRestBundle was created for these purposes. And I think you should start to use it in your project. It has no overhead and is easy to use.
https://github.com/FriendsOfSymfony/FOSRestBundle
Regards.
I recently have had a need to something like this as I am extensively using AngularJS whose $http service sends data as JSON to my controllers.
I found a solution by implementing service which listens to incoming requests unpacks JSON and exposes it to Request object.
Check "The right way" section of this link.
Related
I have created a REST API using the Yii2 documentation. It seems to be working fine as I can use curl like this:
curl -i "https://example.com/api/v3/user" \
-H "Accept:application/json" \
-H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
I would now like to be able to consume this data from another Yii2 site. I am trying to use the Yii2 REST API client. I won't post the whole code as it's basically a copy of the Facebook client in yiisoft/yii2-authclient.
Does anyone know of a guide to help me amend this to comsume my API? In the first instance, I'm struggling with what to put for $authUrl and $tokenUrl.
I am not sure if you need to extend outh2 class as I believe you don't have the authentication logic completed in the first Yii2 webapp, like authenticating using first webapp url then redirect to the second webapp to extract the token from url.
It could be simpler just create a component that have those methods
class YourRestClient {
const BASE_URL = 'https://example.com/api/v3';
private $_token = null;
public function authenticate($username,$password){
$client = new Client();
$response = $client->createRequest()
->setMethod('POST')
->setUrl(BASE_URL.'/user/login')
->setData(['username' => $username, 'password' => $password])
->send();
if ($response->isOk) {
$this->_token = $response->data['token'];
}
}
public function logout(){
//your logut logic
}
public function refreshToken(){
//your refresh logic
}
public function userList(){
$client = new Client();
$response = $client->createRequest()
->setMethod('GET')
->setUrl(BASE_URL.'/user/users')
->addHeaders([
'content-type' => 'application/json',
'Authorization' => 'Bearer '.$_token,
])
->send();
if ($response->isOk) {
return $response->getData();
}
}
}
for more info httpclient
If I am not wrong what you will need for this, is to use yiisoft/yii2-httpclient
Ref: https://github.com/yiisoft/yii2-httpclient
Add it: php composer.phar require --prefer-dist yiisoft/yii2-httpclient
Then make the call «I would probably build a model to handle this»
use yii\httpclient\Client;
$client = new Client();
$response = $client->createRequest()
->setMethod('GET')
->setUrl('https://example.com/api/v3/user')
->addHeaders(['Authorization' => 'Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'])
->send();
if ($response->isOk) {
// use your data
}
I have made PHP Slim server. Authentication for it and CSRF.
I want to use it as a REST Server.
I have a created an App using IonicFramework which uses Angular.
I want to authenticate myself with this code
let hheaders:Headers=new Headers();
hheaders.append('Access-Control-Allow-Origin' , '*');
hheaders.append('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT');
hheaders.append('Accept','application/json');
let options = new RequestOptions({ headers:hheaders});
let data = new FormData();
data.append("email", this.myForm.email);
data.append("password", this.myForm.password);
data.append("csrf_name", this.myForm.csrf_name);
data.append("csrf_value", this.myForm.csrf_value);
return this.http.post('http://10.1.3.101:8088/public/auth/signinservice',data,this.options)
.map(res => res.json())
.toPromise();
But I always get Failed CSRF check! I do not know what is the problem. At this point the Slim Server is basic. It is very simple and similar to this Github project with new methods in AuthController.php
like
public function getSignInService($request, $response){
$nameKey = $this->csrf->getTokenNameKey();
$valueKey = $this->csrf->getTokenValueKey();
$name = $request->getAttribute($nameKey);
$value = $request->getAttribute($valueKey);
$tokenArray = [
$nameKey => $name,
$valueKey => $value
];
return $response->write(json_encode($tokenArray));
}
and
public function postSignInService($request, $response, $args){
$auth = $this->auth->attempt(
$request->getParam('email'),
$request->getParam('password')
);
if(!$auth){
$data = array('status' => 'error');
$newResponse = $response->withJson($data, 203);
return $newResponse;
}
$data = array('status' => 'Successful login');
$newResponse = $response->withJson($data, 200);
return $newResponse;
}
and added routes for the methods.
How could i successfully authenticate with Ionic v3 and Angular v5?
Is there any way to mock response and request in Guzzle?
I have a class which sends some request and I want to test.
In Guzzle doc I found a way how can I mock response and request separately. But how can I combine them?
Because, If use history stack, guzzle trying to send a real request.
And visa verse, when I mock response handler can't test request.
class MyClass {
public function __construct($guzzleClient) {
$this->client = $guzzleClient;
}
public function registerUser($name, $lang)
{
$body = ['name' => $name, 'lang' = $lang, 'state' => 'online'];
$response = $this->sendRequest('PUT', '/users', ['body' => $body];
return $response->getStatusCode() == 201;
}
protected function sendRequest($method, $resource, array $options = [])
{
try {
$response = $this->client->request($method, $resource, $options);
} catch (BadResponseException $e) {
$response = $e->getResponse();
}
$this->response = $response;
return $response;
}
}
Test:
class MyClassTest {
//....
public function testRegisterUser()
{
$guzzleMock = new \GuzzleHttp\Handler\MockHandler([
new \GuzzleHttp\Psr7\Response(201, [], 'user created response'),
]);
$guzzleClient = new \GuzzleHttp\Client(['handler' => $guzzleMock]);
$myClass = new MyClass($guzzleClient);
/**
* But how can I check that request contains all fields that I put in the body? Or if I add some extra header?
*/
$this->assertTrue($myClass->registerUser('John Doe', 'en'));
}
//...
}
#Alex Blex was very close.
Solution:
$container = [];
$history = \GuzzleHttp\Middleware::history($container);
$guzzleMock = new \GuzzleHttp\Handler\MockHandler([
new \GuzzleHttp\Psr7\Response(201, [], 'user created response'),
]);
$stack = \GuzzleHttp\HandlerStack::create($guzzleMock);
$stack->push($history);
$guzzleClient = new \GuzzleHttp\Client(['handler' => $stack]);
First of all, you don't mock requests. The requests are the real ones you are going to use in production. The mock handler is actually a stack, so you can push multiple handlers there:
$container = [];
$history = \GuzzleHttp\Middleware::history($container);
$stack = \GuzzleHttp\Handler\MockHandler::createWithMiddleware([
new \GuzzleHttp\Psr7\Response(201, [], 'user created response'),
]);
$stack->push($history);
$guzzleClient = new \GuzzleHttp\Client(['handler' => $stack]);
After you run your tests, $container will have all transactions for you to assert. In your particular test - a single transaction. You are interested in $container[0]['request'], since $container[0]['response'] will contain your canned response, so there is nothing to assert really.
I have this simple REST api, done in Slim,
<?php
require '../vendor/autoload.php';
function getDB()
{
$dsn = 'sqlite:/home/branchito/personal-projects/slim3-REST/database.sqlite3';
$options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
try {
$dbh = new PDO($dsn);
foreach ($options as $k => $v)
$dbh->setAttribute($k, $v);
return $dbh;
}
catch (PDOException $e) {
$error = $e->getMessage();
}
}
$app = new \Slim\App();
$app->get('/', function($request, $response) {
$response->write('Bienvenidos a Slim 3 API');
return $response;
});
$app->get('/getScore/{id:\d+}', function($request, $response, $args) {
try {
$db = getDB();
$stmt = $db->prepare("SELECT * FROM students
WHERE student_id = :id
");
$stmt->bindParam(':id', $args['id'], PDO::PARAM_INT);
$stmt->execute();
$student = $stmt->fetch(PDO::FETCH_OBJ);
if($student) {
$response->withHeader('Content-Type', 'application/json');
$response->write(json_encode($student));
} else { throw new PDOException('No records found');}
} catch (PDOException $e) {
$response->withStatus(404);
$err = '{"error": {"text": "'.$e->getMessage().'"}}';
$response->write($err);
}
return $response;
});
$app->run();
however, I can't get browser to send me application/json content type, it
always sends text/html? What I am doing wrong?
EDIT:
Ok, after two hours of hitting the head against the wall, I stumbled upon this answer:
https://github.com/slimphp/Slim/issues/1535 (at the bottom of a page)
which explains what happens, appears that response object is immutable and
as such it must be returned or reassigned if you want to return it after
while.
So, instead of this:
if($student) {
$response->withHeader('Content-Type', 'application/json');
$response->write(json_encode($student));
return $response;
} else { throw new PDOException('No records found');}
Do like this:
if($student) {
return $response->withStatus(200)
->withHeader('Content-Type', 'application/json')
->write(json_encode($student));
} else { throw new PDOException('No records found');}
And all is well and good.
For V3, withJson() is available.
So you can do something like:
return $response->withStatus(200)
->withJson(array($request->getAttribute("route")
->getArgument("someParameter")));
Note: Make sure you return the $response because if you forget, the response will still come out but it will not be application/json.
For V3, the simplest method as per the Slim docs is:
$data = array('name' => 'Rob', 'age' => 40);
return $response->withJson($data, 201);
This automatically sets the Content-Type to application/json;charset=utf-8 and lets you set a HTTP status code too (defaults to 200 if omitted).
You can also use:
$response = $response->withHeader('Content-Type', 'application/json');
$response->write(json_encode($student));
return $response;
because withHeader return new response object. That way you have more then one write and code between.
I have read Testing in Symfony2 book but did not find any useful to do this so, I'm creating test for controllers in my application and this is the controller (just relevant code) I'm trying to test:
public function createCompanyAction(Request $request) {
$response = array();
$response["success"] = false;
try {
if (statement) {
// do the magic here
$response["success"] = true;
} else {
$response['errors'] = "some error";
}
} catch (Exception $ex) {
$response["exception"] = $ex->getMessage();
}
return new JsonResponse($response);
}
The test will pass only if $response has TRUE value in success key but I don't know how to check that from my test controller. This is the code I have:
$client->request('POST', '/create-company', $data);
$response = $client->getResponse();
$this->assertEquals(200, $client->getResponse()->getStatusCode(), 'HTTP code is not 200');
$this->assertTrue($response->headers->contains('Content-Type', 'application/json'), 'Invalid JSON response');
$this->assertNotEmpty($client->getResponse()->getContent());
How I check this?
I answer myself. Searching trough Google I found JsonResponse tests and I found how to test it, so I transform my code into this:
$client->request('POST', '/create-company', $data);
$response = $client->getResponse();
// Test if response is OK
$this->assertSame(200, $client->getResponse()->getStatusCode());
// Test if Content-Type is valid application/json
$this->assertSame('application/json', $response->headers->get('Content-Type'));
// Test if company was inserted
$this->assertEquals('{"success":"true"}', $response->getContent());
// Test that response is not empty
$this->assertNotEmpty($client->getResponse()->getContent());
I have not tested yet but it may works.