My normal web app runs w/o any issue. Then I wanted to experiment with APIs. I enabled Passport since I need api authorization (but at this moment, I rather want to get this thing working and I have no idea whether it is a problem with Passport) and I wanted to get simple json output of specific Product. So far, I was not able to get it working. I'll describe contents of each file and if someone can direct me to find the issue in my code, that would be great.
Resources\Product.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Product extends JsonResource
{
public function toArray($request)
{
return parent::toArray($request);
}
}
Providers\AuthServiceProviders.php
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
User.php
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
...
}
ProductController.php
class ProductController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function apiShow(Product $product)
{
return new ProductResource($product);
}
...
}
routes/api.php
Route::get('/products/{product}', 'ProductController#apiShow');
Now if I go to http://localhost/public/products/1, it displays the page as expected. But if I type in http://localhost/public/api/products/1, it will always go to home page which is set to localhost/public in HomeController.
If I modify routes/api.php as:
Route::get('/products/{id}', function($id) {
return Product::find($id);
});
I get the correct json output in the browser.
Related
I'm new to swagger and have it installed and running but it's picking up far more API files than desired. I have been hunting a way to specify which API is documented.
You can put an ApiExplorerSettings attribute on a controller to remove it from Swagger:
[ApiExplorerSettings(IgnoreApi = true)]
public class TestApiController : ControllerBase
{
}
If you want to apply this on a lot of controllers based on some logic,
it can be done e.g. with an action model convention: https://github.com/juunas11/AspNetCoreHideRoutesFromSwagger/blob/983bad788755b4a81d2cce30f82bc28887b61924/HideRoutesFromSwagger/Controllers/SecondController.cs#L18-L28
public class ActionHidingConvention : IActionModelConvention
{
public void Apply(ActionModel action)
{
// Replace with any logic you want
if (action.Controller.ControllerName == "Second")
{
action.ApiExplorer.IsVisible = false;
}
}
}
The convention is added in ConfigureServices like:
services.AddControllers(o =>
{
o.Conventions.Add(new ActionHidingConvention());
});
I am new in using policies in Laravel. I am learning API Development using Laravel. My codes are as bellows.
TopicPolicy.php
<?php
namespace App\Policies;
use App\User;
use App\Topic;
use Illuminate\Auth\Access\HandlesAuthorization;
class Topicpolicy
{
use HandlesAuthorization;
public function update(User $user, Topic $topic)
{
return $user->ownsTopic($topic);
}
public function destroy(User $user, Topic $topic)
{
return $user->ownsTopic($topic);
}
}
AuthServiceProvider.php
<?php
namespace App\Providers;
use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
}
TopicController.php
<?php
namespace App\Http\Controllers;
use App\Topic;
use App\Post;
use Illuminate\Http\Request;
use App\Http\Requests\StoreTopicRequest;
use App\Transformers\TopicTransformer;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
class TopicController extends Controller
{
public function destroy(Topic $topic) {
$this->authorize('destroy',$topic);
$topic->delete();
return response(null,204);
}
}
I am getting error This action is unauthorized.. I don't know how to use policies. Could anyone guide me to use policies in Laravel 5.5.14 ?
In the AuthServiceProvider class you have to register the policy in the policies aray. Laravel documents is a good place to start
protected $policies = [
\App\Topic::class => \App\Policies\Topicpolicy::class
]
Second obtain a personal token from your app so you can use it to make calls to your api. You use passport and passport comes with ready to use Vue components to help you start.If you want to consume the api inside the same application check here.
I am not sure what you try to accomplice with the HandlesAuthorization trait inside the policy. Laravel has a middleware for this reason for us to use.
Trying to figure out why something like the below cant work. There is a tab in the preferences admin section that points to this controller but when going to it it always output a blank page. I have tried several things but the below is basically what I need. There is no MODEL... I simply need this to get the uploaded file for postProcessing...
The controller file...
class AdminAstroImporterController extends ModuleAdminController {
public function initContent() {
parent::initContent();
return $this->display(__FILE__, 'import.tpl');
}
public function postProcess() {
//do something here
}
}
Looks like you can overide the actual content output by doing as shown in the initContent() function shown below. The 'content' in the smarty assign can be any html you generate yourself.
class AstroImporterAdminController extends AdminController {
public function __construct() {
parent::__construct();
//load current settings
$this->data = unserialize(Configuration::get('ASTRO_IMPORTER'));
}
public function initContent() {
parent::initContent();
$this->show_toolbar = false;
$this->context->smarty->assign(array(
'content' => $this->renderSettings().$this->renderForm().$this->displayFields(),
));
}
I found that this works:
public function renderList()
{
global $currentIndex, $cookie;
$smarty = $this->context->smarty;
$smarty->assign('currentIndex', $currentIndex);
return $this->context->smarty->fetch($this->getTemplatePath().'/main.tpl');
}
Although its dirty as hell, it seems cleaner than Amb3rL4nn answer.
In v1.4 it was very easy to create a tab (and easy to find documentation) I wonder why they changed it and didn't supply an docs.
I have two models with a one-to-many relationship.
class User extends ConfideUser {
public function shouts()
{
return $this->hasMany('Shout');
}
}
class Shout extends Eloquent {
public function users()
{
return $this->belongsTo('User');
}
}
This seem to work fine.
BUT, How do I get this to return the users object nested in the shout objects?
Right now it only returns all my Shouts, but I have no access in the JSON to the belonging user model.
Route::get('api/shout', function() {
return Shout::with('users')->get();
});
This just returns this JSON, with no user object for every shout:
[{"id":"1","user_id":"1","message":"A little test shout!","location":"K","created_at":"2013-05-23 19:51:44","updated_at":"2013-05-23 19:51:44"},{"id":"2","user_id":"1","message":"And here is an other shout that is a little bit longer...","location":"S","created_at":"2013-05-23 19:51:44","updated_at":"2013-05-23 19:51:44"}]
I was having the same trouble using Laravel 5. Just wanted to add that I got it to work by using the Model::with("relationship")->get() method on the model.
I figured it out.
The method needs to be named user() not users() when working with "belongsTo" relationship.
Makes sense.
And seems to work.
If you are using:
protected $visible = ['user'];
Don't forget to add there relationship, to be visible in JSON
u can use protected $with = ['users']; on Class Shout and use protected $with = ['shouts'];.
and Give Full namespace model name
class Shout extends Eloquent {
protected $with = ['users'];
public function users()
{
return $this->belongsTo('App\User');
}
}
and
class User extends ConfideUser {
protected $with = ['shouts'];
public function shouts()
{
return $this->hasMany('App\Shout');
}
}
Receive It
Route::get('api/shout', function() {
return Shout::all()->toJson;
});
I'm switching a Zend Framework application from mono-user to multi-user.
What is the best approach to include the user scope in the controllers ?
One way would be to add the user id in each methods in every controllers:
/application/controllers/IndexController.php
...
public function indexAction() {
$params['user_id'] = Zend_Auth::getInstance()->getIdentity()->id;
$listHelper->readItems($params);
}
...
An other one would be to create a new User model and fetch his items :
/application/controllers/IndexController.php
...
public function indexAction() {
$userModel = new application_models_user();
$userModel->find(Zend_Auth::getInstance()->getIdentity()->id);
$userModel->readItems();
}
...
I'm wondering what's the best approach that would allow me to write minimal code and if you have another idea to "automagically" add the user scope (db scope, plugin...).
Create an abstract class by extending Zend_Controller_Action
abstract class My_Controller_Action extends Zend_Controller_Action {
private $userModel;
public function getUserModel() {
if(is_null($this->userModel)) $this->userModel = new application_models_user();
return $this->userModel;
}
public function getUserId() {
return $this->getUserModel()->find(Zend_Auth::getInstance()->getIdentity()->id);
}
}
Now use this class as base class for your controllers.