API between two separate instances of Laravel - php

I am trying to figure out a problem I have. I have 2 laravel setups on the same server, each are independent sites controlled via vhosts.
SiteA needs to act as an API to SiteB. So within SiteA I set up an API by doing
Route::group(['prefix' => 'api/v1'], function () {
Route::post('postProject', array('as' => 'postProject', 'uses' => 'APIController#postProject'));
});
For now, the controller function is simply this
public function postProject(Project $project)
{
dd($project);
}
So within SiteB I want to call this API. As such, I set up a route which contains the project object (I have tried both get and post)
Route::get('projects/{projects}/postProject', array('as' => 'projects.postProject', 'uses' => 'APIController#postProject'));
And this controller function does the following
public function postProject($project)
{
$client = new GuzzleHttp\Client();
$req = $client->request('POST', 'http://localhost/api/v1/postProject', [
'body' => $project,
'headers' => [
'Content-Type' => 'text/xml',
'Content-Length' => strlen($project),
]
]);
$output = $req->getBody()->getContents();
return $output;
}
I have localhost as an example url so the real url wasnt exposed. The error siteB receives when making the post request is a 404 not found. If on siteA I set up a simple get function that returns something, siteB can execute this API call without any problem. The problem comes about when I am trying to post something from siteB to siteA.
Additionally, when I pass the $project object, is there any way to send over its related models as well? A $project has one to many relationships with a few other models, and ideally I would like to get the related data over.

I think you just need to eager load the relationships
public function postProject()
{
//dd($project);
Project::with('relation1', 'relation2')->find($id);
}

Related

Laravel 5.4 - form/API/view

I created an API (store) that saves the data on the database and returns 201 if successful or 404 if not.
if ($visit->save()){
$visit->view_visit = [
'href' => 'api/v1/visit/' . $visit->id,
'method' => 'GET'
];
$response = [
'msg' => 'Visit created.',
'visit' => $visit
];
return response()->json($response, 201);
}
$response = [
'msg' => 'Error during creation.'
];
return response()->json($response, 404);
It works perfectly. Using postman you can see that the status will be <<201 Created>>.
This API should be used in two ways: called by another application or called by a Laravel form. This is the question:
How do I call it in a way if it successful, it will load a given view on the browsers?
In other words, is there a way to make the form call a route (the api itself, something like ../api/visit/) and in case of success loads the other view? Also, I would like to pass the content of response['msg'] to this new view.
I know I could do it inside the store method by filtering the HTTP referrer, but I would like to keep the controller code strictly to manage the record creation. Besides that, I have to send the 201/404 codes along with the returned data.
I also considered creating another controller to handle the API response and then call the form, but it still sounds too much -- it's supposed to be easy, I guess.
In laravel you can use a helpful method which determines if the request that has been sent is an AJAX request or just a normal request, which is:
$request->wantsJson()
So, Inside your controller in the return function, you will make an if statement:
if ($request->wantsJson()) {
return response()->json();
}else{
return view(...);
}

Laravel 5.2 PHPUnit JSON Api request body not being set

I am testing POSTing data to an API endpoint we've created using Laravel 5.2, but none of the parameters seem to be reaching the application in the test. The endpoint expects json and responds with json and uses a FormRequestValidator which has required rules for active and make parameters. The test fails with status code 422 and the examining the response body it states the active and make parameters are required even though they are being passed in the call so therefore for some reason when the request reaches the the Form Request Validator, the input is not there.
However, when I invoke the endpoint with json body including make and active from Postman or the UI app we've built it works fine, it is only failing in the PHPUnit tests therefore it must be something with PHPUnit or the test setup being incorrect. Here is the test:
public function testItStoresCars()
{
// Arrange
$user = User::first();
//Act
$this->json(Request::METHOD_POST, '/v1/cars', [
'active' => true,
'make' => 'Audi'
],
['Authorization' => 'Bearer '.\JWT::fromUser($user)]));
// Assert
$this->assertResponseOk();
}
I know the Authorisation header is set correctly from other tests passing.
I've tried disabling middleware, using the $this->post helper method and manually setting the headers as well as using the $this->call method with setting the Headers and encoding the data using json_encode but I always get the same 422 response. I'm wondering has anyone encountered this issue or can see an error?
Controller Code
public function store(CreateCarRequest $request)
{
$car = $this->carRepo->save($request->all());
return response()->json(car);
}
FormRequest
class CreateCarRequest extends Request
{
public function rules()
{
return [
'active' => 'required|boolean',
'make' => 'required',
];
}
}
422 is the error response for validation errors.. which means either your data is not posted or it doesn't pass server validation, try
$this->json(Request::METHOD_POST, '/v1/cars', [
'active' => true,
'make' => 'Audi'
],
['Authorization' => 'Bearer '.\JWT::fromUser($user)]))->dump();
dump() should show you the errors

Passing data from a route to a controller [Laravel]

I would like to pass a variable from my routes file to the controller specified. Not using parameters as the information is not in the URL. I can't figure out a way to pass it using the below code.
Route::get('faqs', [
'as' => 'thing',
'uses' => 'Controller#method',
]);
I know you can redirect to a controller as well but the error says that the method does not exist and after searching I found that the controller had to be assigned to a route and after that it was still the same error but in a different location.
Any thoughts?
One way this can be achieved is by creating custom middleware by adding your custom fields to the attributes property.
So you would do;
$request->attributes->add(['customVariable' => 'myValue']);
You can use Route::bind to assign value for specific slug
Route::bind('parameter', function($parameter)
{
return SomeModel::where('name',$parameter)->first();
});
Route::get('faqs/{parameter}', [
'as' => 'thing',
'uses' => 'Controller#method',
]);
And in your controller set this as a method parameter
public function method(SomeModel $model)
{
dd($model);
}

Why is my create form request throwing off a 404 exception in Laravel5?

So I am working with a Laravel 5 installation and like a good programmer I am trying to get the validation logic out of my controller using the new Form Requests feature in Laravel.
So I went ahead and created a form request called CreateTenantRequest like so:
php artisan make:request CreateTenantRequest
By default it returns a false in the authorize method and it works correctly. If I fire a request, it says forbidden. But then I updated the rules and I set the authorize method to true and now when I fire the same request from Postman, it says:
NotFoundHttpException in RouteCollection.php line 161:
Which is ridiculous because when I change it to false, it returns forbidden fine?
What am I missing or doing wrong?
And although this wouldn't matter I guess but my rules array is as follows:
return [
// Tenant details
'name' => 'required|max:255',
'username' => 'required|max:255|unique:tenant',
// Tenant Admin details
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required|email|max:255',
'password' => 'required|confirmed|min:6',
];
Routes file:
<?php
Route::group(['prefix' => 'api'], function(){
Route::post('authenticate', 'Auth\AuthController#authenticate');
// SuperAdmin Group
Route::group(['namespace' => 'Archive', 'middleware' => 'superadmin'], function(){
Route::resource('tenants', 'TenantController');
Route::get('tenants/{id}/users', 'TenantController#showUsersForTenant');
});
// Tenant Group
Route::group(['namespace' => 'Tenant'], function(){
Route::resource('roles', 'RoleController');
Route::resource('users', 'UserController');
});
// Remove before production
// Only for testing purposes
Route::get('test', function(){
// return JWTAuth::parseToken()->getPayload()->get('username');
});
});
So after a bid discussion with shock_gone_wild, I realized that the request was not ajax and hence laravel was rerouting to the a url with the errors in session.
I was testing the API with Postman REST client and by default it sends basic HTTP requests but when a header is added like so:
X-Requested-With:XMLHttpRequest
It makes the request Ajax and then laravel checks to see if it is indeed ajax, so instead of routing to a url, it gave back the validation errors in JSON.
So anytime if anyone is creating a decoupled web service and trying to test it using Postman, do it with the header so that you can simulate actual ajax requests at your application.

Request data from Laravel API into wordpress

I am working on a project on laravel 5.1, and i want to make it as a RESTFUL api so later we can use the same code and request data from mobile apps or other websites. The project is in its initial stages and i want to make it correct right from the beginning.
Suppose i have a simple route which is calling a the dashboard method on the AdminController. So after logging in it redirects the admin to the dashboard page with some data.
/******************** Laravel Project ***********************/
//Routes.php
Route::group(['middleware' => 'auth'], function () {
Route::get('dashboard', 'AdminController#dashboard');
});
// AdminController
public function index(){
$data = 'Some Data';
return view( 'superadmin.dashboard')->with('data', $data );
}
Now i want to get the same data in a wordpress project. How will i use this api to just fetch the data variable (without the view) ? I dont want to create another method for that, is there any way i can use the same function to fetch data as a json?
I read in another forum that we can access all the data as a REST like this. But this is not working.
http://admin:admin123#example.dev/dashboard
As always appreciate your help :)
Personally, I would create an application that is the API. In your case this is your Laravel application.
Then I'd make HTTP requests to the API from Wordpress, or a mobile application.
I find returning JSON from the API is easier to work with. Laravel makes this easy:
return Response::json(array(
'username' => 'superadmin',
'role' => 'admin',
'friends' => array(
'2345',
'884'
)
));
Also, don't send your username and password like that. HTTP auth is insecure. http://adrianotto.com/2013/02/why-http-basic-auth-is-bad/
I tend to use OAuth to secure my APIs.

Categories