- REST - REpresentational State Transfer
- Orientado a resources (recursos)
- Stateless
- HTTP status code
- HTTP methods (GET, POST, PUT, DELETE)
- HTTP headers
- Negociação de content-type
2xx - Tudo certo
3xx - Alteração de estado ( não usado no REST por ser stateless )
4xx - Erro no cliente
5xx - Erro no servidor
200 - Tudo ok
301 - Redirecionamento permanente
302 - Redirecionamento Temporário
404 - Página não encontrada
422 - Falha na validação
500 - Erro no servidor
Authorization: bearer <token>
Content-Type: application/x-www-form-utlenconded
Content-Type: application/json
Accept: application/json
mkdir laravel_rest && cd laravel_rest
composer create-project --prefer-dist laravel/laravel
echo "CREATE DATABASE curso_laravel_rest_2" | mysql -uroot -p`-
Edite o .env informando o DB_DATABASE=curso_laravel_rest_2 e tambem usuario e senha do banco
-
php artisan serve
php artisan make:model Product -mc- A flag
-mcindica a criação da migration e do controler juntamente com a model. - A flag
-mrindica a criação de um controler do tipo resource com método index, store, e outros que são padrões do laravel. - Na migration criada indicaremos os seguintes campos:
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('body');
$table->timestamps();
});- Abra o arquivo routes/api.php e crie a seguinte rota:
Route::prefix('v1')->group(function() {
Route::get('/products', 'ProductController@index');
});- Abra o controller e crie o método index:
use App\Product;
class ProductController extends Controller
{
public function index()
{
return Product::all();
}
}php artisan migrate- Acesse a url http://localhost:8000/api/v1/products
- Abra o controler e crie um novo método com nome
store
public function store(Request $request)
{
return Product::create($request->all());
}- Abra as rotas da api e inclua uma rota post no grupo já criado anteriormente
Route::post('/products', 'ProductController@store');- Baixe o app postman para testar
- Envie uma requisição POST para http://localhost:8000/api/v1/products
- Na aba
Bodydo postman, escolha a opçãox-www-form-urlencodede crie os campostitleebodycriados na migration - Preencha os campos com valores e envie a requisição.
- Vai acontecer um erro na requisição porque é necessário configurar o model primeiro.
- Abra o model Product e informe os campos preenchiveis.
protected $fillable = ['title', 'body'];- Envie a requisição post novamente e tudo ocorrerá bem.
- Verifique no banco de dados se o registro foi inserido
echo "SELECT * FROM curso_laravel_rest_2.products" | mysql -uroot -p
- Crie uma nova rota para atualizar os registros:
Route::put('/products/{product}', 'ProductController@update'); - O parametro nomeado na rota put precisa ser o nome do model (
product) para que seja feito um binding implicito durante a requisição. - Crie o método update no Controller para fazer a atualização do registro:
public function update(Request $request, Product $product)
{
$product->update($request->all());
return $product;
}- O método update receberá como segundo parametro a injeção do model product.
- Modifique os dados do Body da requisição e faça uma nova requisição put na url: http://localhost:8000/api/v1/products/1
- Crie agora uma nova rota get para listar apenas um produto:
Route::get('/products/{product}', 'ProductController@show'); - Crie o método show:
public function show(Product $product)
{
return $product;
}- Faça a requisição na mesma url anterior do put porem dessa vez com o método get para obter o recurso desejado informando o seu id.
- Agora para finalizar crie a rota para delete:
Route::delete('/products/{product}', 'ProductController@destroy'); - E tambem o método destroy:
public function destroy(Product $product)
{
$product->delete();
return $product;
}- Utilize a mesma url de update porem utilizando o método http delete para remover o item.
- Após remover o recurso, faça uma requisição get do método index do controller para ver que é retornado uma collection vazia.
- Para facilitar as coisas, não é necessario declarar todas aquelas rotas como vimos anteriormente.
- Se seguirmos este padrão utilizado pelo laravel e API's REST, podemos substituir todas aquelas rotas por apenas uma do tipo resource
Route::prefix('v1')->group(function() {
Route::resource('products', 'ProductController@index');
});- Faça testes com os métodos post, get, put e delete com as mesmas URL's utilizadas anteriormente para testar as rotas que o tipo resource nos fornece.
- Alem do metodo estatico de rotas do tipo
Resource, tambem existe o método estaticoResources(no plural), onde podem ser declarados diversos recursos de uma vez inseridos em um array associativo de recursos e controllers.
Route::resources([
'products' => 'ProductController',
'users' => 'UserController'
]);- Um comando do artisan pode ser usado para cirar controllers já com métodos para recursos:
php artisan make:controller --resource UserController- Este controller gerado ainda vem com dois métodos extras, são eles o
createe oeditque são para telas de formularios para criação e edição de itens. Em API's REST estes métodos nao são utilizados nos controllers. - O model e a migration para user já existem por padraõ em aplicações laravel. Agora que foram criadas as rotas e o controller para este recurso, você já pode testa-lo.
- Faça testes com os diversos metodos http no postman para o recurso user, lembrando que os campos disponiveis para envio estão declarados na migration. (name, email, password)
- Veja que ao fazer a inserção de um novo registro, as informações retornadas como json são apenas name e email. Isso acontece porque o campo password está declarado no model no array de nome $hidden
- Crie uma Request para Product com o comando:
php artisan make:request ProductRequest - Abra o request criado (
app/Http/Requests/ProductRequest) e altere o métodoauthorizepara retornartrue; - Defina as regras de validação no método rules:
return [
'title' => 'required',
'body' => 'required|min:10'
];- Agora abra o Controller de Product e troque o caminho do namespace de Request usado para o caminho do Request criado e dê um alias para ele como Request para que não precise Substituir o nome em outras partes do mesmo arquivo.
- Antes:
use Illuminate\Http\Request;. Depois:use App\Http\Requests\ProductRequest as Request - Agora faça uma requisição Post sem enviar nunhum dado no body e você receberá um erro informando a mensagem de campos requiridos
- Caso você seja redirecionado em uma versão anterior do laravel, é ncessário enviar como cabeçalho da requisição, o campo seguinte: "X-Requested-With": "XMLHttpRequest" ou então o campo "Accept": "Application/json"
- As mensagens são retornadas em inglês porem, é possivel traduzi-las para seu idioma com o laravel
composer require laravel/passportphp artisan migrate. Para fazer as migrations de autenticaçãophp artisan passport:install. Copie os dados gerados para um arquivo declarado no .gitignore.- Abra a model User e declare:
use Laravel\Passport\HasApiTokens;para usar o Trait - Tambem delcare dentro da classe:
use HasApiTokens, Notifiable; - Abra o arquivo
app/Providers/AuthServiceProvider.php;e declare:use Laravel\Passport\Passport; - No método boot() do
AuthServiceProvideradicione uma linha no final:Passport::routes(); - Agora abra o arquivo
config/auth.php;e na propriedade'guards' => 'api' => 'drive', altere o valor'token'para'passport'. - Já podemos testar a rota POST
http://localhost:8000/oauth/tokenpara receber um erro de acesso.
php artisan vendor:publish --tag=passport-components. Para publicar dentro deresources/assets/js/componentsalguns componentes vue.- Abra o arquivo
resources/assets/js/app.js - Adicione as seguintes linhas para registrar os compoentes gerados no subdiretorio
components/passport:
Vue.component('passport-clients', require('./components/passport/Clients.vue'));
Vue.component('authorized-clients', require('./components/passport/AuthorizedClients.vue'));
Vue.component('personal-access-tokens', require('./components/passport/PersonalAccessTokens.vue'));- Agora instale as dependencias de front-end com
npm install. - Digite
php artisan make:authpara publicar o scaffold de algumas novas views de authenticação emresources/views. - Na view
layout/app.blade.phpa tag script que faz referencia ao asset modificado anteriormente estará inserido. - Abra a view
home.blade.phpe insira a tag do componente<passport-clients></passport-clients>logo abaixo do textoYou are logged in!para testar. - Insira tambem as tags dos outros dois componentes para que possamos ve-los ao fazer o primeiro login.
- Agora o arquivo
public/js/app.jsprecisa ser atualizado com o conteudo adicionado noresources/assets/js/app.js - Execute o comando
npm run devpara atualizá-lo. - Vamos então acessar a rota raiz
http://localhost:8000e registrar um novo usuário. - Crie um usuario e faça login para ver os componentes gerados.
- Vamos agora fazer testes no postman
- Crie uma nova requisição POST para o endereço
http://localhost:8000/oauth/token - No body da requisição vamos cadastrar alguns campos:
grant_type: passwordclient_id: 1 ou 2 dependendo de qual key você for utilizarclient_secret: coloque aquela chave gerada e guardada no arquivo ingorado pelo .gitignoreusername: email do usuario recem cadastradopassword: senha do usuario cadastradoscope: permissões que você quer ter acesso (deixe em branco)
- Caso dê algume erro de cliente invalido, use o comando
php artisan passport:client --passwordpara gerar uma nova client_id e client_secret. - A requisição irá te retornar um access_token e um refresh_token. Copie o access_token para darmos continuidade.
- Abra o arquivo
routes/api.phpe adicione o middleware de autenticação antes do prefix da nossa rota.
Route::middleware('auth:api')->prefix('v1')->group(function() {
Route::resources([
'products' => 'ProductController',
'users' => 'UserController'
]);
});- Agora as nossas rotas estarão protegidas.
- Tente fazer uma requisição em
/api/v1/productse você receberá a mensaggem de erroUnauthenticated.. - Para fazer acesso às rotas protegidas pelo middleware de authenticação, é necessário passar um novo Header de requisição.
- Crie o cabeçalho
Authorizatione cole o valor copiado deaccess_tokenda rota/oauth/tokenmas antes dele coloque o nomeBearere separe-o do token com um espaço. - Pronto, agora ja com o token no cabeçalho, faça novamente uma requisição em
/api/v1/products. - Esta forma de autenticação é segura se for feita em aplicações que rodam no backend pois o
client_secretutilizado para obter oaccess_tokenestá protegido no servidor. Porem em aplicações front-end ou mobile não dá para guardar essa key, nesse tipo de aplicação é necessário utilizar um proceso de autenticação chamado de implicit grant. - Abra o arquivo
app/Providers/AuthServiceProvider.phpe declare no método boot() apósPassport::routes();a o seguinte:Passport::enableImplicitGrant();. - Ativado o impicit grant, vamos agora acessar pelo navegador no endereço:
http://localhost:8000/oauth/authorize?client_id=3&response_type=code&scope=&redirect_uri=http://meusite.com/pagina-de-loginpassando alguns parametros pela url. - Acesse a rota
/homedepois de fazer login comum no laravel clique emCreate new Clientno componente vue gerado anteriormente. - Preencha os campos Name e Redirect URL com os valores passados na query na url do implicit grant: Meu site e http://meusite.com/pagina-de-login
- O componente vue vai gerar um novo id e secret.
- Agora acesse novamente a url alterando o id para o que foi informado pelo componente vue.
- A página irá pedir permissão para acessar sua conta, semelhante ao login feito por meio do google, facebook, twitter, dropbox, github e outros.