web-dev-qa-db-fra.com

Comment créer une REST première application Web API dans Laravel

Je veux faire une première application API à Laravel. Je ne sais pas quelle est la meilleure approche pour le faire, je vais expliquer ce que j'essaie de faire, mais n'hésitez pas à donner des réponses sur la façon de le faire d'une manière différente.

Je ne veux pas que tout mon frontend soit écrit en javascript et analyse la sortie JSON de l'API avec angular.js ou quelque chose de similaire. Je veux que mon application Laravel pour produire les vues HTML. J'essaie de suivre la voie d'avoir deux contrôleurs un pour l'API et un pour le web. Pour le show Action utilisateur mes routes .php ressemble à ceci:

# the web controller
Route::controller('user', 'WebUserController');

# the api controller 
Route::group(array('prefix' => 'api'), function() {
    Route::resource('user', 'UserController');
});

Donc /user M'emmènera à WebUserController et /api/user M'amènera à UserController. Maintenant, je veux mettre toute ma logique dans l'API UserController, et appeler ses actions depuis WebUserController. Voici le code pour les deux:

class UserController extends BaseController 
{
    public function show($id)
    {
        $user = User::find($id);
        return Response::json(array('success'=>true,'user'=>$user->toArray()));
    }
}

class WebUserController extends UserController 
{
    public function getView($id) 
    {
         # call the show method of the API's User Controller
         $response =  $this->show($id);
         return View::make('user.view')->with('data', $response->getData());
    }
}

Dans le WebUserController je peux obtenir le contenu json de la réponse avec getData(), mais je ne peux pas obtenir les en-têtes et le code d'état (ce sont des propriétés protégées de Illuminate\Http\JsonResponse).

Je pense que mon approche n'est peut-être pas la meilleure, donc je suis ouvert aux suggestions sur la façon de créer cette application.

[~ # ~] modifier [~ # ~] : la question comment obtenir les en-têtes et l'état de la réponse a été répondue par Drew Lewis , mais je pense toujours qu'il pourrait y avoir une meilleure façon de concevoir ce

28
Martin Taleski

Vous devez utiliser le modèle de conception de référentiel/passerelle: veuillez voir les réponses ici .

Par exemple, lorsque vous traitez avec le modèle utilisateur, créez d'abord un référentiel utilisateur. La seule responsabilité du référentiel d'utilisateurs est de communiquer avec la base de données (effectuer des opérations CRUD). Ce référentiel utilisateur étend un référentiel de base commun et implémente une interface contenant toutes les méthodes dont vous avez besoin:

class EloquentUserRepository extends BaseRepository implements UserRepository
{
    public function __construct(User $user) {
        $this->user = $user;
    }


    public function all() {
        return $this->user->all();
    }

    public function get($id){}

    public function create(array $data){}

    public function update(array $data){}

    public function delete($id){}

    // Any other methods you need go here (getRecent, deleteWhere, etc)

}

Ensuite, créez un fournisseur de services, qui lie votre interface de référentiel d'utilisateurs à votre référentiel d'utilisateurs éloquent. Chaque fois que vous avez besoin du référentiel d'utilisateurs (en le résolvant via le conteneur IoC ou en injectant la dépendance dans le constructeur), Laravel vous donne automatiquement une instance du référentiel d'utilisateurs Eloquent que vous venez de créer. Il en est ainsi que, si vous changez les ORM en quelque chose d'autre qu'éloquent, vous pouvez simplement changer ce fournisseur de services et aucune autre modification de votre base de code n'est requise:

use Illuminate\Support\ServiceProvider;

class RepositoryServiceProvider extends ServiceProvider {

    public function register() {
        $this->app->bind(
            'lib\Repositories\UserRepository',        // Assuming you used these
            'lib\Repositories\EloquentUserRepository' // namespaces
        );
    }

}

Ensuite, créez une passerelle utilisateur, dont le but est de parler à n'importe quel nombre de référentiels et d'exécuter toute logique métier de votre application:

use lib\Repositories\UserRepository;

class UserGateway {

    protected $userRepository;

    public function __construct(UserRepository $userRepository) {
        $this->userRepository = $userRepository;
    }

        public function createUser(array $input)
        {
            // perform any sort of validation first
            return $this->userRepository->create($input);
        }

}

Enfin, créez votre contrôleur Web utilisateur. Ce contrôleur parle à votre passerelle utilisateur:

class UserController extends BaseController 
{
    public function __construct(UserGatway $userGateway)
    {
        $this->userGateway = $userGateway;
    }

    public function create()
    {
        $user = $this->userGateway->createUser(Input::all());

    }
}

En structurant ainsi la conception de votre application, vous obtenez plusieurs avantages: vous réalisez une séparation très claire des préoccupations, car votre application respectera le principe de responsabilité unique (en séparant votre logique métier de votre logique de base de données). Cela vous permet d'effectuer des tests unitaires et d'intégration d'une manière beaucoup plus facile, rend vos contrôleurs aussi minces que possible, ainsi que vous permet d'échanger facilement Eloquent pour toute autre base de données si vous le souhaitez à l'avenir.

Par exemple, si vous passez d'Eloquent à Mongo, les seules choses que vous devez changer sont la liaison du fournisseur de services ainsi que la création d'un MongoUserRepository qui implémente l'interface UserRepository. C'est parce que le référentiel est la seule chose qui parle à votre base de données - il n'a aucune connaissance d'autre chose. Par conséquent, le nouveau MongoUserRepository pourrait ressembler à quelque chose comme:

class MongoUserRepository extends BaseRepository implements UserRepository
{
    public function __construct(MongoUser $user) {
        $this->user = $user;
    }


    public function all() {
        // Retrieve all users from the mongo db
    }

    ...

}

Et le fournisseur de services va maintenant lier l'interface UserRepository au nouveau MongoUserRepository:

 $this->app->bind(
        'lib\Repositories\UserRepository',       
        'lib\Repositories\MongoUserRepository'
);

Dans toutes vos passerelles, vous avez référencé UserRepository, donc en faisant cette modification, vous dites essentiellement Laravel d'utiliser le nouveau MongoUserRepository au lieu de l'ancien Eloquent. Aucune autre modification n'est requise.

42
seeARMS

Vous devez utiliser le référentiel pour cette conception.

Exemple -

//UserRepository Class
class UserRepository {
    public function getById($id)
    {
      return User::find($id);
    }
}

// WebUser Controller
class WebUserController extends BaseController {
    protected $user;

    public function __construct(UserRepository $user)
    {
        $this->user = $user;
    }

    public function show($id)
    {
        return View::make('user.view')->with('data', $this->user->getById($id));
    }
}

// APIUser Controller
class UserController extends BaseController {
    protected $user;

    public function __construct(UserRepository $user)
    {
        $this->user = $user;
    }

    public function show($id)
    {
        $data =>$this->user->getById($id);
        return Response::json(array('success'=>true,'user'= $data->toArray()));
    }
}
7
Nyan Lynn Htut

Ceci est une vidéo de Jeffrey Way, il est l'un des meilleurs développeurs Laravel. Dans ce tutoriel, il connecte une application BackboneJS à un service RESTful qu'il installe à Laravel. Il ne reçoit pas mieux que ça. Je peux vous écrire beaucoup de passe-partout, mais apprenez-le simplement en regardant une belle vidéo et en buvant un café.;)

https://www.youtube.com/watch?v=uykzCfu1RiQ

2
sidneydobber

Découvrez les contrôleurs RESTful de Laravel:

http://laravel.com/docs/controllers#restful-controllers

Leurs documents font du très bon travail.

Mais encore mieux est ce tutoriel:

http://code.tutsplus.com/tutorials/laravel-4-a-start-at-a-restful-api-updated--net-29785

2

J'ai une réponse au problème que vous rencontrez avec la réponse. Vous pouvez obtenir les en-têtes, le code d'état et les données de la réponse.

// your data
$response->getData();

// the status code of the Response
$response->getStatusCode(); 

// array of headers
$response->headers->all();

// array of headers with preserved case
$response->headers->allPreserveCase(); 

$ response-> headers est un Symfony\Component\HttpFoundation\ResponseHeaderBag qui hérite de Symfony\Component\HttpFoundation\HeaderBag

1
lagbox

Je recommanderais également d'utiliser un référentiel. Tenter d'appeler un contrôleur à partir d'un autre reviendrait à un modèle appelé HMVC (Hierarchical model – view – controller). Cela signifie que l'ensemble de votre application repose sur des modules inférieurs. Dans ce cas, votre API servirait de référentiel pour vos données (ce qui n'est pas la pire chose au monde au premier abord).

Cependant, lorsque vous modifiez ensuite la structure de la façon dont les données sont renvoyées dans votre API, tout le reste qui en dépend devra savoir comment réagir. Supposons que vous vouliez effectuer des vérifications d'autorisation pour voir si un utilisateur connecté devrait pouvoir voir les détails d'un utilisateur renvoyé et il y a eu une erreur.

Dans l'API, vous renverriez un objet Response avec un code interdit 403 et des métadonnées. Votre contrôleur HTML devrait savoir comment gérer cela.

Comparez cela à un référentiel qui pourrait lever une exception.

public function findById ($id)
{
    $user = User::findOrFail($id);

    if (Auth::user->hasAccessTo($user)) {
        return $user;
    } else {
        throw new UnauthorizedAccessException('you do not have sufficient access to this resource');
    }
}

Et votre contrôleur API ressemblerait plus à ceci:

public function show($id)
{
    try {
        return $this->user->findById($id);
    } catch (UnauthorizedAccessException $e) {
        $message = $e->getMessage();
        return Response::json('403', ['meta' => ['message' => $message]]));
    }
}

Votre contrôleur HTML ressemblerait alors à ceci:

public function show($id)
{
    try {
        $user = $this->user->findById($id);
    } catch (UnauthorizedAccessException $e) {
        Session::flash('error', $e->getMessage());
        // Redirect wherever you would like
        return Response::redirect('/');
    }
}

Cela vous donne un code très réutilisable et vous permet de changer les implémentations de votre contrôleur indépendamment sans vous soucier de changer le comportement de l'autre. J'ai écrit plus sur la façon d'implémenter le modèle de référentiel dans ce post : vous pouvez ignorer l'interface et passer directement aux implémentations si vous le souhaitez.

1
Ryan Tablada