Boas Práticas em APIs Com Laravel — Part 2 — Endpoints

Olá amigos! Nesta segunda parte da série de artigos "Boas Práticas em Apis com o Laravel" vamos introduzir o conceito de Endpoints, mais especificamente RESTful.
O que é RESTful?
Diferente do SOAP, que é uma especificação, o REST é algo mais abstrato: um estilo arquitetural. Ele é formado por um conjunto de regras no topo do protocolo HTTP que foram comunicadas pela primeira vez por Roy Fielding em sua tese de doutorado. Depois de seu surgimento, começou a se tornar uma alternativa mais leve de comunicação entre computadores (cliente e servidor). (fonte)
Controllers RESTful no Laravel
No Laravel temos uma forma bem interessante de trabalhar com Rotas/Controllers RESTfull, tem um recurso chamado Resource.
php artisan make:controller FilmsController --resource --model=FilmDesta forma será criado Controller com todos os métodos RESTFul declarados e também será criado uma Model que é passada como parâmetro dentro de alguns métodos do controller criado.
Em seguida, nos registraremos uma rota resourceful(do tipo resource) para o controller:
Route::resource('films', 'FilmsController',
['except' => [
'create', 'edit'
]]);
// in routes/api.phpEsta declaração única cria múltiplas rotas, com uma variedade de ações RESTful no resource de films. Da mesma forma, o controller gerado irá ter os métodos prontos para cada ação, incluindo notas informando a você as URIs e verbos que elas manipulam.
Verb | Path | Action | Route Name
----------|-----------------------|--------------|------------------
GET | /films | index | films.index
POST | /films | store | films.store
GET | /films/{films} | show | films.show
PUT/PATCH | /films/{films} | update | films.update
DELETE | /films/{films} | destroy | films.destroyVocê pode estudar mais a respeito dos controllers e rotas na própria documentação do Laravel.
Vamos falar mais a respeito de cada verbo que foi citado acima:
ROTAS e VERBOS
- GET /films — Esta rota usaremos para gerar a nossa lista de dados/paginação ( como preferir chamar), em resumo é onde será listado nossos Filmes, de acordo com o exemplo que estamos usando. Esta é a página inicial da nossa lista de rotas.
- POST /films — Esta rota é utilizada para enviar os dados a serem salvos. Ou seja ela recebe o POST que cria um novo registro.
- PUT /films/{films} — Esta rota é mais utilizada atualizar um determinado registro. Nela voce pode passar um parâmetro (ID) do registro.
- PATCH /films/{films} — Esta rota é idêntica a de cima, também serve para atualizar um registro, muda o VERBO de PUT para PATCH.
- DELETE /films/{films} — Esta é bem Implícita né? Ela é responsável por deletar um registro.
POST vs PUT
Eu vejo bastante artigos dizendo que PUT é feito para inserir e POST para atualizar e vice-versa, mas vamos ver o que o RFC diz:
Se você olhar para a página 55 do RFC 2616 (“Protocolo de transferência de hipertexto — HTTP / 1.1”), seção 9.6 ("PUT"), você verá o que PUT é realmente:
O método PUT solicita que a entidade incluída seja armazenada sob o Pedido-URI fornecido.
Há também um parágrafo útil para explicar a diferença entre POST e PUT:
A diferença fundamental entre as solicitações POST e PUT é refletida no diferente significado do Request-URI. O URI em uma solicitação POST identifica o recurso que irá lidar com a entidade incluída. Esse recurso pode ser um processo de aceitação de dados, um gateway para algum outro protocolo ou uma entidade separada que aceita anotações. Em contraste, o URI em uma solicitação PUT identifica a entidade anexada ao pedido — o agente do usuário sabe o que o URI está destinado e o servidor NÃO DEVE tentar aplicar a solicitação a algum outro recurso.
Não menciona nada sobre a diferença entre atualizar / criar, porque não é o que se trata.
Você pode encontrar a documentação RFC aqui
Plural, Singular ou Ambos?
Este é um conceito um tanto discutido e com opiniões diversas. Eu particularmente prefiro usar as ROTAS e Controllers no Plural e Models no Singular, é um padrão que eu adotei e pretendo seguir. Mas você tem a liberdade de escolher como preferir.
Configurando nosso Controller
<?phpnamespace App\Http\Controllers;use App\Film;
use Illuminate\Http\Request;class FilmsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return response()->json(['data'=> Film::all()]);
} /**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255',
'slug' => 'required|unique:films|max:255',
'release' => 'required',
'locale' => 'required',
'duration' => 'required',
'sinopse' => 'required',
'cover' => 'required',
]); return Film::create($request->all());
} /**
* Display the specified resource.
*
* @param \App\Film $film
* @return \Illuminate\Http\Response
*/
public function show(Film $film)
{
return response()->json(['data'=> $film]); } /**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Film $film
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Film $film)
{
$this->validate($request, [
'name' => 'required|max:255',
'slug' => 'required|unique:films|max:255',
'release' => 'required',
'locale' => 'required',
'duration' => 'required',
'sinopse' => 'required',
'cover' => 'required',
]); $film = $film->fill($request->all()); return response()->json(['data'=> $film]);
} /**
* Remove the specified resource from storage.
*
* @param \App\Film $film
* @return \Illuminate\Http\Response
*/
public function destroy(Film $film)
{
$film->delete(); return response()->json(['data'=> 'Deleted']);
}
}
Pronto! Nosso controller configurado é só testar.
DEIXE DE LADO O AUTO INCREMENTO!
É isso mesmo! Esqueça o auto-incremento para o desenvolvimento de apis. É fácil assumir que, se estamos na página /films/10 a anterior é /films/9 e sucessivamente, isso pode gerar grandes problemas. Um exemplo que ficou conhecido na comunidade é o do Trampos.co
Então veja bem, usar um UUID é uma boa forma de resolver este problema., assim acabamos com as sequências numéricas (Chave primária sequencial) e tornamos nossa aplicação bem mais segura.
Neste artigo é isso. Mas vejamos, o Laravel não fornece uma resposta apropriada para os erros que podem acontecer com nossas rotas não é mesmo? No próximo artigo falaremos a respeito de Status Codes, Errors and Messages.
Obs: Atualmente está sendo bastante falado a respeito do graphQL, que é um assunto bastante interessante também! Mas nesta série de artigos eu estou preferindo seguir os conceitos trazidos pelo Phil Sturgeon. Mas sinta-se a vontade para aplicar da forma com bem entender os conceitos trazidos aqui =)
Não se esqueça de deixar seu feedback! Até
Veja o código do artigo no github
Referencias:
