Laravel REST API and frontend - laravel

I created a project in Laravel, small database and added REST API in laravel to connect mobile app with database. What should I use to get data from database in web application? Using laravel models is easy but is that a good way to create another controllers to handle forms etc instead using rest api controllers? Thanks

Laravel also support for Restful API in own way.
for this
you create your controller in Api folder: php artisan make:controller Api/TestController
define your routes in routes/api.php :
Route::group(['namespace' => 'Api'], function (){
Route::group(['prefix' => '/test'], function () {
Route::get('/', 'TestController#list);
Route::get('/single', 'TestController#single');
});
});
create a resource collection for data that is an array of collection
php artisan make:resource Api/Collections TestCollection this command create a collection in folder app/Http/Resources/Api/Collections
open in and change toArray($request) function and add a function with($request) like following code :
public function toArray($request)
{
return $this->collection->map(function ($item){
return [
'id' => $item->id, // $item is instance of Test model
'name' => $item->name,
'description' => $item->description,
];
});
}
public function with($request) // optional : this method return with of response
{
return [
'status' => true
];
}
so go to TestController and create a method for get all tests:
public function list()
{
$tests = Test::all(); // your Test Model
return new TestCollection($test); // TestCollection you created above
}
this is return a json object that contains array of tests.
for get a single test :
php artisan make:resource Api/Resources TestResource
then go to TestResource in app/Http/Resources/Api/Collections and change code like following:
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name, // $this is instance of Test model
'description' => $this->description,
'body' => $this->body,
'diff_name' => $this->name_in_table // you can change the name differ from name in model instance
];
}
so go to TestController and create a method for single test
public function single(Request $request)
{
$test = Test::findOrFail($request->id);
return new TestResource($test);
}
this a summary of Rest API in laravel. Hope you find it useful

With laravel, you can reuse your api endpoints by taking advantage of the CreateFreshApiToken middleware.
Then you will only need to create new controllers and methods to display views. All of the CRUD stuff can be reused.

Related

How to create Laravel api route endpoint/query parameters?

I would like to be able to filter the json response using some fields in the database e.g. api/v1/user?username=mary but don't know how to do this. My second question is that the route api/v1/user/3 is working but I can't remember how I set this up as I did it some time ago. Can anyone help?
api.php
Route::group(['prefix' => 'v1'], function () {
Route::apiResource('/user', 'UserController');
});
user resource
public function toArray($request)
{
return parent::toArray($request);
}
user controller
public function show(User $user): UserResource
{
return new UserResource ($user);
}
public function index(): UserResourceCollection
{
return new UserResourceCollection(User::orderBy('created_at', 'desc')
->paginate(5)
);
}
public function store(Request $Request)
{
$request->validate([
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required',
]);
$user = User::create($request->all());
\Mail::to($user)->send(new Welcome);
return new UserResourse($user);
}
public function update(User $user, Request $request): UserResource
{
$user->update($request->all());
return new UserResource($User);
}
public function destroy(User $user)
{
$user->delete();
return response()->json();
}
}
UPDATED
I have seen several tutorials with the advice that the user has given below but I don't know how to put it together because I already have a show method above. I tried commenting out the show method and creating another show method for the query string
public function show(User $user): UserResourceCollection
{
$request->input('username');
return new UserResourceCollection(User::orderBy('created_at', 'desc')
->where('username', '=', $username)
->paginate(2)
);
}
and added a GET route
Route::group(['prefix' => 'v1'], function () {
Route::apiResource('/user', 'UserController');
Route::get('/user/{username?}','UserController#show');
});
This is working as an endpoint. The pagination part is working I made it smaller so I know it's calling the method but it is searching by id and i want to search by username. Ideally I want to use a query parameter like api/v1/user?username=mary.
To get json request, you can call $request->input('name') for example.
You can setup the resource action on controller. By example, you can create UserController.show method. So, the GET /user/{id} method will be handled by UserController.show
For more example, you read the documentation.
I don't think it's possible to create api url parameters. I started again using this tutorial
https://www.youtube.com/watch?v=z3YPhYwcbBM.
This way means I always have to know the id (search by product id rather than filtering reviews by query search) which isn't ideal
e.g. http://localhost:8000/api/v1/products/2/reviews
however I can add more endpoints in place of reviews like categories etc.

Laravel - custom id

I'm trying to make my custom ID for table posts. And I found haruncpi laravel id generator and I installed it with this command.
composer require haruncpi/laravel-id-generator.
After that I add use Haruncpi\LaravelIdGenerator\IdGenerator; to my PostsController. And now i need to add this snippet to my model.
$id = IdGenerator::generate(['table' => 'posts', 'length' => 10, 'prefix' =>'INV-']);
But I don't know where and how... Maybe in public function store() or somewhere else? Please help!
I just want my id to be like:
INV-000001
INV-000002
...
Laravel models has a boot() method, where you can register calls related to your model. Therefor you can subscribe to the creating event, which will fire before the model is saved and you can mutate the model in the process.
So in your Post.php model, add the following.
public static function boot()
{
parent::boot();
self::creating(function ($model) {
$model->id= IdGenerator::generate(['table' => 'posts', 'length' => 10, 'prefix' =>'INV-']);
});
}
And as long as you utilize basic Laravel functionality, it will add the id to the model.

Laravel multi authetification with different users tables

I'm trying to build a multiple authentification in laravel with different tables (2 tables) for admin and user. The problème is that the registration and login forms work only with default auth login/register.
I've tried some examples form web tutorials but it didn't work.
HomeController.php:
public function __construct() {
$this->middleware('auth');
}
public function index() {
return view('home');
}
I have added createAdmin function in "Auth/RegisterController.php":
protected function createAdmin(array $data)
{
$this->validator($data->all())->validate();
$admin = Admin::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
return redirect()->intended('login/admin');
}
I have changed email validation rules to:
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'|'unique:admins']
And the route (web.php) is:
Route::post('/register/admin', 'Auth\RegisterController#createAdmin');
When I fill admin register credentials and click register button I get this message:
Symfony\Component\Debug\Exception\FatalThrowableError Too few arguments to function App\Http\Controllers\Auth\RegisterController::createAdmin(), 0 passed and exactly 1 expected
The error is coming from the array $data parameter in your createAdmin() controller method.
Usually, you want to use one of two types of parameters in your controller methods: route parameters or injected dependencies. The $data parameter isn't matching either of those, so Laravel doesn't know to provide it.
If you'd like to access the request (POST) data in the controller, you can either ask for an instance of Illuminate\Http\Request as a parameter:
// Import it at the top of your PHP file
use Illuminate\Http\Request;
// Then your updated method:
public function createAdmin(Request $request)
{
$data = $request->all();
// ...
}
Or, use the request() helper directly:
public function createAdmin()
{
$data = request()->all();
// ...
}

Executing function before every controller request

I'm calling cloud APIs using token authentication with php-openstack-sdk.
$openstack = new OpenStack\OpenStack([
'authUrl' => '{authUrl}',
'region' => '{region}',
'user' => [
'id' => '{userId}',
'password' => '{password}'
],
'scope' => ['project' => ['id' => '{projectId}']]
]);
However, every API call requires me to be authenticated (as shown in the code above). Instead of repeating the same auth code in every controller function, how do I do it once and be able to call $openstack in my controller's functions? i.e., in my controller, I can directly use $openstack.
public function listServers()
{
$openstack->computeV2()->listServers();
}
Write the logic in the __construct() of your Controller.php if you want that to be accessible for all the controllers. If not, write the __construct() within the controller you need.
Controller.php
class Controller extends BaseController
{
protected $openstack;
public function __construct()
{
$this->openstack = new OpenStack\OpenStack([
...
]);
}
}
NetworkController.php
class NetworkController extends Controller
{
public function getNetworkDetails() {
$network = $this->openstack->networking();
}
}
You can place the code shown in the __construct function of your controller and provide it as a protected variable to the class.
I think the best way is to use laravel middlewares

Auth::user() returns null on Module __construct()

I created a new Module named Article using laravel-modules. Some backend routes needed authentication and i added auth middleware and an additional permission view_backend. I am using https://github.com/spatie/laravel-permission package for role-permissions.
the issue is when i try to access the route admin/article/posts it prompts me the login as expected. But after login it show null on __construct() method for Auth::user();
I added web middleware as mentioned on #204 but it did not solve the issue. Can you please guide me to resolve this? My project is on Laravel 5.6 and using the latest version of Laravel-Modules
Route::group(['namespace' => 'Modules\Article\Http\Controllers\Backend', 'as' => 'backend.article.', 'middleware' => ['web', 'auth', 'can:view_backend'], 'prefix' => 'admin/article'], function () {
Route::resource("posts", "PostsController");
});
My project is hosted at Github, https://github.com/nasirkhan/laravel-starter/tree/module
First of all, add Spatie Middleware to your kernel:
protected $routeMiddleware = [
// ...
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
];
Then in your controller check for permission or roles:
public function __construct(Request $request)
{
$this->middleware(['permission: order.index']);
}
Now you can access to your authenticated with $request->user() like:
public function create(Request $request)
{
if ($request->user()->hasRole('admin')) {
// return view("carmodel.create", ["manufacturers"=>$manufacturers]);
} else {
return view("admin.error", ['code'=>'001','msg'=>'err']);
}
}
According to the docs:
In previous versions of Laravel, you could access session variables or the authenticated user in your controller's constructor. This was never intended to be an explicit feature of the framework. In Laravel 5.3, you can't access the session or authenticated user in your controller's constructor because the middleware has not run yet.
As an alternative, you may define a Closure based middleware directly
in your controller's constructor. Before using this feature, make sure
that your application is running Laravel 5.3.4 or above:
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->projects = Auth::user()->projects;
return $next($request);
});
}
Or you could typehint it:
public function index(Request $request)
{
$projects = $request->user()->projects;
$value = $request->session()->get('key');
}
Docs

Resources