I already have Laravel web pages where i can add/update/delete/Read records from MySQL Database. Laravel version is 5.2.15
Now, I have to integrate Database with Android App. In order to do that I have to post and read Json Data.
Here question is: Should I have 2 public action methods? First for web page that will show records on webpage and second will return json data in Android.
I meant, when I return data to webPage..I will have to write the below code.
return View("View-Path", array("Data" => $Data));
but in case of Android App, I will have to request Json Data.
Please suggest the right approach.
You should develop a simple API to access your APP data from an android client:
Routes
First of all you need to create some specific routes for the API through which you'll serve your data in JSON format
Authentication
The API's routes should handle authentication in a different way in respect on what you're doing now: you can't use the classic session-based approach. Instead you have to use a basic or token-based approach. You've different alternatives, these are some of the most used (from the simplest, to the most complicated )
Laravel HTTP Basic Authentication
Laravel Json Web Token Authentication
Laravel OAUTH2
Data Acess
Once you've setup your routes and authentication, you have to serve your data via the API routes. Since you use the same data in your APP routes and API routes, you can wrap the logic of data building and retrieving in services, and use the services to get the data both in your APP routes and API routes.
Using different controllers for API and APP routes, you have:
//APP Controller method for route: www.app.com/app-route/users
public function getUsers()
{
//wrap the logic to build the data inside the service
$service = App::make('your_service');
//once is ready, get the built data from the service
$data = $service->getData();
return View("View-Path", array("Data" => $data));
}
//API Controller method for route: www.app.com/api/users
public function getUsers()
{
//use the same service to build and get the data you need
$service = App::make('your_service');
$data = $service->getData();
return response()->json( $data );
}
This way you can:
Encapsulate data building and retrieveng in services, so that you don't have the need to duplicate code for data retrieving between APP and API routes
Have different controllers to access APP or API routes; so you can get the data, transform it as you need and serve it to either views or api clients
About the Service class
Regarding the service class i've mentioned, it could be simply one or multiple wrapper classes that you use both in API and APP controllers to build and get the data without repeting code. The structure of such classes depends on how your app work.
For example let's suppose you need to compute some data for each user's project, store it in a variable and then send it to the viev:
public function getUsers($request)
{
$user = Users::with('projects')->find( $request->user_id )->get();
$data = [];
foreach ( $user->projects as $p )
{
//compute some data you need and store it in $data;
}
return View("View-Path", array("Data" => $data));
}
Now if want to make the same thing in the API controller, you'd need to repete this code to get the projects and create the data. To avoid this, you could 'wrap' the data access in a service class, and use the same class in boh controllers:
Service class
public class UserDataBuilder
{
protected $user;
public function setUser( Authenticatable $user )
{
$this->user = $user;
}
public function getData()
{
$user = Users::with('projects')->find( $this-user->id )->get();
$data = [];
foreach ( $user->projects as $p )
{
//compute some data you need and store it in $data;
}
return $data;
}
}
and use the same class in both API and APP controllers:
//APP controller: get the data and pass to the view
public function getUsers($request)
{
$service = App::make( UserDataBuilder::class );
$service->setUser( User::find( $request->user_id )->get() );
return View("View-Path", array("Data" => $service->getData() );
}
//API controller: get the data and convert to JSON
public function getUsers($request)
{
$service = App::make( UserDataBuilder::class );
$service->setUser( User::find(1)->get() );
return response()->json( $data );
}
For android you have to write a separate web service.
You can use one method to do that. Example
public function someMethod(Request $request){
$Data = ['laravel','is','awesome'];
// If the request has the content type is json return a json response
// So you android request will be true for this request
// else return data to webpage
if($request->isJson()){
return response()->json($Data);
}
return View("View-Path", array("Data" => $Data));
}
Related
I'm using Woocommerce webhooks to listen out for every time an order is created/updated/deleted.
I've setup the webhook in Woocommerce as follows
In my Laravel routes file I have set up the route as follows:
use Illuminate\Http\Request;
// API routes...
Route::post('api/v1/orders/create', function (Request $request) {
Log::debug($request->all());
return $request->all();
});
However, when I view the logs as well as the return data in POSTMAN, all I get is an empty array.
Any HTTP method other than 'GET' throws a MethodNotAllowedException
I'm not sure of any other way in Laravel to consume data other than with Request $request.
According to my understanding of routing in Laravel, the input that you pass in to the function is meant to actually be variables for your route.
So if you had a route in your API:
api/v1/orders/{id}/create then in the route function you'd pass in id as the method argument. So this would be correct:
Route::post('api/v1/orders/{id}/create', function ($id) {
Log::debug($id);
return $id;
});
It's looking for request in your route definition.
Rather create a controller. Then in your routes.php use this:
Route::post('api/v1/orders/create', 'OrdersController#create')
That tells your routing to redirect all HTTP POST calls to api/v1/orders/create to the OrdersController.php and the create() method within that controller.
In your controller, you'll be able to use the $request variable as an input argument and it should work.
So in OrdersController.php:
class OrdersController extends Controller {
public function create(Request $request) {
Log::debug($request->all());
return $request->all();
}
}
Good Luck!
This worked for me. My route in api.php is as follow.
Route::post('/woocommerce/webhook/', 'Api\WoocommerceController#test');
And my controller action is as follow.
public function test()
{
$payload = #file_get_contents('php://input');
$payload = json_decode( $payload, true);
\Log::info(json_encode( $payload));
return response()->json([ 'data' => $payload, 'status' => \Symfony\Component\HttpFoundation\Response::HTTP_OK]);
}
I have a problem with one of my controllers either in Laravel or Ember. I can get the record to save after filling out the form but the record will not persist to the database. Again the form saves the record but doesn't push the record to the database. I tried following Embers guides on pushing data to the server but no juice. Also thanks for all the help from this site, you have got me this far, hopefully I can get this worked out with your help. Here are the controllers,
Laravel Controller
$statusCode = 200;
$libraries = $request->all();
$library = Library::create($libraries);
$criteria = $library->toArray();
return Response::json([
'libraries' => $criteria],
$statusCode);
Ember Route
model() {
return this.store.createRecord('library');
},
actions: {
saveLibrary(item) {
item.save().then(() => this.transitionTo('libraries'));
},
willTransition() {
//rollbackAttributes() removes the record from the store
// if model is 'isNew'
this.controller.set('model').rollbackAttributes();
}
}
In controller, you should use transitionToRoute. and implement POST request for /libraries for save method call.
actions: {
saveLibrary() {
//You dont need to pass. you need to update model properties. and then call save method.
this.get('model').save().then(() => this.transitionToRoute('libraries'));
}
}
I am building a RESTful api in Laravel, with my front end app in Angular.
I have a number of models / controllers and routes. I am struggling to get to grips with creating restful route for nested resources.
For example, my route to show a list of clients is simple:
Route::resource('clients', 'ClientsController');
A client can have many campaigns:
class Client extends Model
{
public function campaigns()
{
return $this->hasMany('App\Campaign');
}
}
I do not need a route to show all campaigns, but I do need a route to show all campaigns based on a client.
Route::resource('clients.campaigns', 'CampaignsController');
My intention was for the endpoint requested by the Angular app to be:
myapp/api/clients/6/campaigns
Where '6' is the client ID. This would return a list of campaigns that belong to client with id 6.
In my index method, I am trying to use implicit model binding to get this client Id, but I always get an empty result set:
class CampaignsController extends ApiController
{
public function index(Client $client)
{
$campaigns = Campaign::where('client_id', $client->id)->get();
if (!count($campaigns)) {
Log::warning('Campaigns list is empty');
return $this->respondNotFound('No Campaigns Found');
}
try {
return $this->respond([
'data' => $this->campaignTransformer->transformCollection($campaigns->all())
]);
} catch (\Exception $e) {
Logging::logException($e, 'API error showing campaigns list');
return $this->respondInternalError('An internal error occurred');
}
}
}
Clearly my route isn't binding a client - a var_dump on $client shows this.
Where am I going wrong?
For anyone who comes across this issue - Laravel was injecting the client_id for me.
Therefore index method becomes:
public function index($client_id)
{
$campaigns = Campaign::where('client_id', $client_id)->get();
}
I am working on my yii2 api and I was looking for a way to get data from my controller actions. This is a sample of what I need on my response in json or xml.
{"success": true,
"message": {data},
"session": "U0phRm51az",
"metadata": "metadata"
}
I am getting message from the controller whereas success checks whether response is OK, session is the session data and metadata is other data.
My actions looks like these.
public function actionIndex(){
$data = array();
}
All these use the same functions so I do not want to repeat in all actions. I would like to know how to get $data from each action using afterAction or beforeSend event of the response component on my module class (not config file). If this is not possible, how can I achieve this?
If your actions return data as an array, you can add more stuff to that array in afterAction method of your controller.
public function actionIndex()
{
//...
//$data contains an array
return [
'data' => $data
];
}
public function afterAction($action, $result)
{
$result = parent::afterAction($action, $result);
$result['session'] = '...';
$result['metadata'] = '...';
return $result;
}
A couple of questions that I cannot seem to find definative answers for, I am working on a RESTful api at the moment, that in time will interact with a handful of client devices, for the time being I am concetrating, on the API, and the web application that goes along with it.
The api lives at http://api.local and the web application lives at http://webapplication.local. The web application is a Laravel installation with a Backbone front-end.
I am trying to save some data from the Backbone to the database of the API. So the API save method looks like this,
public function store()
{
$user_details = Input::all();
$user = new User;
$user->firstname = $user_details['firstname'];
$user->surname = $user_details['surname'];
$user->email = $user_details['email'];
$user->password = Hash::make($user_details['password']);
$user->remember_token = '';
$user->save();
return Response::json($user_details, 200);
}
And it has a route that looks like this,
Route::group(['prefix' => 'api/v1'], function(){
Route::get('users', 'UsersController#index');
Route::get('users/{id}', 'UsersController#get');
Route::post('users/create', 'UsersController#store');
/**
* PUT request to edit the database record
* #todo: Need to be a PUT request in the long run
*/
Route::post('users/update/{id}', 'UsersController#update');
/**
* DELETE request to edit the database record
* #todo: Need to be a DELETE request in the long run
*/
Route::post('users/delete/{id}', 'UsersController#delete');
});
On the front end side (web application) I am saving a model like this,
saveNewUser: function(e) {
e.preventDefault()
var data = this.$el.find('.js-create-new-user').serializeJSON();
// create a new model
var User = new app.User();
User.save(data, {
success: function(model, response){
console.log(model);
console.log(response);
console.log("sucess");
},
error: function(model, response) {
console.log(model);
},
wait:true
});
}
This sends a POST request to the webapplication.local/users/create method, that looks like this,
public function create()
{
$data = Input::all();
$curl = new Curl\Curl();
$curl->post('http://pops.local/api/v1/users/create', $data);
if ($curl->error) {
return Response::json($curl->error, $curl->error_code);
}
else {
return Response::json($curl->response, 200);
}
}
If I look at the $curl->response then I see the data object that is being sent - which I assume means the cURL request is successfully being sent. However nothing gets updated in the API's database?
Am I going about this all wrong? Should Backbone be sending/making requests directly to the API, and leave the PHP behind the web application to do things that the API does not do i.e resize images etc?
You may send requests directly from backbone but you dont have to. Everything looks fine. Check what is returned from $user->save(); by writing something like that:
dd($user->save());
You should get true if everyting is fine, false if there is any error.