Criar e consumir uma API RESTful no PHP Laravel

June 25, 2019
Escrito por
Michael Okoh
Contribuidor
As opiniões expressas pelos colaboradores da Twilio são de sua autoria

Criar e consumir uma API RESTful no PHP Laravel

Desde suas redes sociais favoritas até os aplicativos bancários que você mais usa, nosso mundo moderno é conduzido por muitas APIs. Neste artigo, você aprenderá a criar uma API RESTful moderna e um aplicativo que implementará a API.

Pré-requisitos

  • PHP 7.1 ou superior
  • Composer
  • MySql
  • Laravel 5.6 ou posterior
  • Postman

Para acompanhar este tutorial, você deve ter um entendimento básico da linguagem PHP. É necessário o conhecimento básico da estrutura Laravel.

Noções básicas sobre o aplicativo

Você vai criar uma API CRUD. CRUD é a sigla em inglês de "Create, Read, Update, and Delete" (Criar, ler, atualizar e excluir). Nossa API terá os seguintes endpoints:

GET /api/students retornará todos os alunos e aceitará solicitações GET.

GET /api/students/{id} retornará um registro de aluno fazendo referência a seu id e aceitando solicitações GET.

POST /api/students criará um novo registro de alunos e aceitará solicitações POST.

PUT /api/students/{id} atualizará um registro existente de aluno fazendo referência a seu id e aceitando solicitações PUT.

DELETE /api/students/{id} excluirá um registro de aluno fazendo referência a seu id e aceitando solicitações DELETE.

O registro do aluno conterá apenas name e course como detalhes. Ao terminar de desenvolver esses endpoints, você vai usá-los para desenvolver um aplicativo real de registros de alunos que utilizará a API.

Configurar o aplicativo Laravel

Para começar, você precisa criar um aplicativo Laravel. Para isso, execute o seguinte comando no terminal:

$ laravel new api-project

Em seguida, altere o diretório atual para a pasta raiz do projeto:

$ cd api-project

Depois, inicie o servidor do Laravel caso ele ainda não esteja em execução:

$ php artisan serve

Você poderá visitar seu aplicativo em https://localhost:8000.

Página principal padrão em Laravel

Depois, execute o seguinte comando para criar um banco de dados para seu aplicativo:

$ mysql -uroot -p

Haverá uma solicitação para você digitar sua senha do MySQL se tiver definido uma ao fazer a autenticação com o MySQL. Execute este comando para criar um banco de dados chamado api-project:

CREATE DATABASE `api-project`;

MySQL root no terminal

Podemos continuar criando um modelo juntamente com uma migration (migração). Para fazer isso, você precisa executar:

$ php artisan make:model Student -m

Um novo arquivo chamado Student.php será criado no diretório app.

NOTA: você terá que editar o arquivo para especificar a tabela do banco de dados com a qual gostaríamos de interagir e os campos que podem ser escritos:

 

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Student extends Model
{
    protected $table = 'students';

    protected $fillable = ['name', 'course'];
}

Além disso, um arquivo de migration (migração) será criado no diretório database/migrations para gerar nossa tabela. Você terá que modificar o arquivo de migration (migração) para name e course que aceitará valores de string.

...
public function up()
{
    Schema::create('students', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->string('course');
        $table->timestamps();
    });
}
...

Em seguida, você pode abrir a pasta do projeto em seu editor de texto preferido e modificar o arquivo .env para inserir suas credenciais de banco de dados adequadas. Isso permitirá que o aplicativo se conecte corretamente ao banco de dados recém-criado:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<your-database-name>
DB_USERNAME=<your-database-username>
DB_PASSWORD=<your-database-password>

Em seguida, você executará a migração usando o seguinte comando:

$ php artisan migrate

Configurar as rotas

Agora que temos a noção básica da configuração do aplicativo, podemos executar o seguinte comando para continuar a criar um controlador que conterá os métodos da nossa API:

$ php artisan make:controller ApiController

Você encontrará um novo arquivo chamado ApiController.php no diretório app\http\controllers. Em seguida, podemos adicionar os seguintes métodos:

...
class ApiController extends Controller
{
    public function getAllStudents() {
      // logic to get all students goes here
    }

    public function createStudent(Request $request) {
      // logic to create a student record goes here
    }

    public function getStudent($id) {
      // logic to get a student record goes here
    }

    public function updateStudent(Request $request, $id) {
      // logic to update a student record goes here
    }

    public function deleteStudent ($id) {
      // logic to delete a student record goes here
    }
}

Vá para o diretório routes, abra o arquivo api.php e crie os endpoints que referenciarão os métodos criados anteriormente no ApiController.

...
Route::get('students', 'ApiController@getAllStudents');
Route::get('students/{id}', 'ApiController@getStudent');
Route::post('students, 'ApiController@createStudent');
Route::put('students/{id}', 'ApiController@updateStudent');
Route::delete('students/{id}','ApiController@deleteStudent');

Nota: todas as rotas em api.php são prefixadas com /api por padrão

Criar um registro de aluno

Localize o método createStudent em nosso ApiController

public function createStudent(Request $request) {
  // logic to create a student record goes here
}

Usaremos a classe de solicitação do Laravel para buscar os dados passados para o endpoint. O endpoint também estará esperando o name do tipo string e também o course do tipo string. Quando tivermos obtidos com êxito os dados, armazenaremos em nosso banco de dados.

...
use App\Student;

class ApiController extends Controller
{
  ...
  public function createStudent(Request $request) {
    $student = new Student;
    $student->name = $request->name;
    $student->course = $request->course;
    $student->save();

    return response()->json([
        "message" => "student record created"
    ], 201);
  }
  ...
}

O trecho de código acima importa o model (modelo) Student que vai interagir com a tabela students no banco de dados. No método createStudent, instanciamos um novo objeto Request no parâmetro do método seguido por um novo objeto Student. Por fim, para cada $student-><column-name>, a solicitação equivalente é obtida e salva.

Se a operação for bem-sucedida, uma resposta JSON será enviada de volta ao usuário da API com a mensagem student record created e com o código de resposta 201.

Esse método já está vinculado a api/students, conforme o definimos anteriormente em nosso arquivo de rotas localizado em routes/api.php:

...
Route::post('students, 'ApiController@createStudent');
...

Testar

Antes de testar, verifique se o aplicativo está em execução. Você pode usar o comando integrado conforme mencionado anteriormente:

$ php artisan serve

Ou você pode usar o Valet que é uma ótima ferramenta para criar uma passagem de proxy para todos os seus aplicativos em PHP, fornecendo um domínio *.test ou *.dev para que seus aplicativos sejam testados localmente.

Para testar este endpoint, abra o Postman e faça uma solicitação POST para http://localhost:8000/api/students ou se você usa o Valet http://<folder-name>/api/students. Selecione a opção form-data e passe os seguintes valores conforme visto na imagem abaixo:

Visualização em Postman da solicitação POST

Ele funcionou se retornar a mensagem de sucesso junto com o código de resposta 201. Agora, tente adicionar mais alguns registros para preencher o banco de dados para a próxima tarefa.

Retornar todos os registros de alunos

Agora, vamos visitar o method (método) getAllStudents no ApiController

public function getAllStudents() {
  // logic to get all students goes here
}

Usaremos o model (modelo) Student já importado para fazer uma consulta eloquent simples para retornar todos os alunos no banco de dados.

class ApiController extends Controller
{
  public function getAllStudents() {
    $students = Student::get()->toJson(JSON_PRETTY_PRINT);
    return response($students, 200);
  }
  ...
}

A consulta eloquent termina com ->toJson(JSON_PRETTY_PRINT); que vai serializar o retorno de dados do objeto por eloquent em um JSON bem formatado. O JSON é retornado com o código de resposta 200.

Este método já está vinculado à rota api/students, conforme o definimos anteriormente em nosso arquivo de rotas localizado em routes/api.php:

...
Route::get('students', 'ApiController@getAllStudents');
...

Testar

Supondo que o aplicativo esteja sendo executado em segundo plano, faça uma solicitação GET para o endpoint /api/students no Postman.

Visualização em Postman da solicitação GET

Como visto na imagem acima, o endpoint retorna todos os registros de alunos no banco de dados.

Retornar um registro de aluno

Você criará um endpoint para retornar apenas um único registro de aluno. Para começar, você precisa visitar o method (método) getStudent no ApiController.

public function getStudent($id) {
  // logic to get a student record goes here
}

Recuperaremos um registro de aluno por seu id e, para isso, faremos uma consulta eloquent para retornar registros de alunos por seu id.

...
class ApiController extends Controller
{
  ...
  public function getStudent($id) {
    if (Student::where('id', $id)->exists()) {
        $student = Student::where('id', $id)->get()->toJson(JSON_PRETTY_PRINT);
        return response($student, 200);
      } else {
        return response()->json([
          "message" => "Student not found"
        ], 404);
      }
  }
  ...
}

O trecho de código acima verifica primeiro se existe um registro de aluno com o id fornecido. Em caso afirmativo, ele consulta o banco de dados usando o eloquent para retornar o registro com o id correspondente no JSON com o código de resposta 200. Se o id fornecido não for encontrado no banco de dados, ele retornará uma mensagem student.not.found com um código de resposta 404.

Este method (método) já está vinculado à rota api/students/{id}, conforme o definimos anteriormente em nosso arquivo de rotas localizado em routes/api.php:

...
Route::get('students/{id}', 'ApiController@getStudent');
...

Testar

Abra o Postman e faça uma solicitação GET para o endpoint /api/students/{id}{id} pode ser id de um registro existente que você pode ter no banco de dados.

Visualização em Postman da solicitação GET para um único registro

Como visto na imagem acima, fiz uma solicitação para http://api-project.test/api/students/3 e os detalhes do aluno atribuído a esse id foram retornados. Em seguida, vamos tentar solicitar um registro de aluno inexistente.

Visualização Postman da solicitação GET para um único registro excluído

Como visto na imagem acima, foi feita uma solicitação ao endpoint para retornar os detalhes do registro de aluno com id de 100 que não existe. Nossa API fez um bom trabalho retornando uma mensagem de erro juntamente com o código de status 404.

Atualizar um registro de aluno

Agora, criaremos um endpoint para atualizar os detalhes de um registro de aluno existente. Para começar, visite o method (método) updateStudent no ApiController.

public function updateStudent(Request $request, $id) {
  // logic to update a student record goes here
}

Para fazer isso, teremos que verificar se o registro que estamos tentando atualizar existe. Se existir, ele atualizará os registros que correspondem ao id especificado e retornará o código de status 204. Se não existir, ele retornará uma mensagem indicando que o registro não foi encontrado junto com o código de status 404.

public function updateStudent(Request $request, $id) {
    if (Student::where('id', $id)->exists()) {
        $student = Student::find($id);
        $student->name = is_null($request->name) ? $student->name : $request->name;
        $student->course = is_null($request->course) ? $student->course : $request->course;
        $student->save();

        return response()->json([
            "message" => "records updated successfully"
        ], 200);
        } else {
        return response()->json([
            "message" => "Student not found"
        ], 404);
        
    }
}

A validação foi adicionada apenas no caso de você precisar atualizar apenas um atributo, como name ou course. Quando a solicitação chega, ela verifica se o name ou o course são nulos. Se for nulo, ele substituirá a solicitação por seu valor existente. Se não for nulo, "null" passou como o novo valor. Tudo isso foi feito com o uso de operadores ternários.

NOTA: O formato do operador ternário é condition? true : false

Este method (método) já está vinculado à rota api/students/{id}, conforme o definimos anteriormente em nosso arquivo de rotas localizado em routes/api.php:

...
Route::put('students/{id}', 'ApiController@updateStudent');
...

Testar

Para testar esse endpoint, retorne os detalhes do registro do aluno com id de 1 fazendo uma solicitação GET para /api/students/1.

Visualização em Postman da solicitação GET para um único registro

Os seguintes registros foram retornados:


    {
        "id": 1

Em seguida, vamos mudar o course para "Engenharia de software" fazendo uma solicitação PUT para api/students/1. Para fazer uma solicitação PUT, você precisa passar um payload JSON pelo form-data. Agora vamos mudar o valor de name para Trojan Okoh e o valor de course para Software Engineering.

{
    "name": "Trojan Okoh",
    "course": "Software Engineering"
}

O trecho de código acima é o payload JSON que usaremos para atualizar os registros. Abra o Postman e altere para raw e altere o tipo para JSON(application/json), conforme mostrado abaixo.

Visualização em Postman para alterar o tipo de dados do formulário

Em seguida, cole o payload JSON na área de texto e envie a solicitação PUT para o endpoint.

Visualização em Postman do registro atualizado

Como visto na imagem acima, o endpoint retornou uma mensagem de sucesso. Agora vamos fazer uma solicitação GET para /api/students/1 para confirmar se os registros foram realmente atualizados.

Visualização em Postman da solicitação GET

Excluir um registro de aluno

Por fim, para excluir um registro de aluno, teremos que visitar o method (método) deleteStudent no ApiController.

public function deleteStudent ($id) {
    // logic to delete a student record goes here
}

Usando o eloquent, verificaremos se existe o id do registro solicitado a ser excluído. Se existir, excluiremos o registro. Se não existir, retornaremos uma mensagem not.found junto com o código de status 404.

...
class ApiController extends Controller
{
    ...
    public function deleteStudent ($id) {
      if(Student::where('id', $id)->exists()) {
        $student = Student::find($id);
        $student->delete();

        return response()->json([
          "message" => "records deleted"
        ], 202);
      } else {
        return response()->json([
          "message" => "Student not found"
        ], 404);
      }
    }
}

Este method (método) já está vinculado à rota api/students/{id}, conforme o definimos anteriormente em nosso arquivo de rotas localizado em routes/api.php:

...
Route::delete('students/{id}', 'ApiController@deleteStudent');

Testar

Para testar esse endpoint, teremos que listar todos os registros que temos atualmente em nosso banco de dados fazendo uma solicitação GET para o endpoint /api/students.

Visualização em Postman da solicitação GET

Em seguida, faremos uma solicitação DELETE para students/{id} na qual {id} é o id do registro para o qual estamos solicitando a exclusão. Para fins de teste, excluirei o registro com o id de 2.

Visualização em Postman do registro excluído

O endpoint retornou uma mensagem de sucesso junto com o código de status 202, o que significa que a solicitação foi aceita. Para confirmar se o registro foi realmente excluído, vamos tentar fazer uma solicitação GET ao endpoint /api/students para listar todos os registros de alunos que temos no banco de dados.

Visualização em Postman de solicitação GET para registros atualizados

Como visto na imagem acima, o registro com o id de 2 não existe mais. Além disso, podemos verificar tentando solicitar o registro com o id de 2 fazendo uma solicitação GET para o endpoint /api/students/{id}. Ele deve retornar 404 indicando que o registro não pôde ser encontrado.

Visualização em Postman de solicitação GET para registro ausente

Conclusão

Agora que você chegou ao fim deste artigo, vamos confirmar o conteúdo de alguns arquivos importantes.

app\http\controllers\ApiController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Student;

class ApiController extends Controller
{
    public function getAllStudents() {
      $students = Student::get()->toJson(JSON_PRETTY_PRINT);
      return response($students, 200);
    }

    public function createStudent(Request $request) {
      $student = new Student;
      $student->name = $request->name;
      $student->course = $request->course;
      $student->save();

      return response()->json([
        "message" => "student record created"
      ], 201);
    }

    public function getStudent($id) {
      if (Student::where('id', $id)->exists()) {
        $student = Student::where('id', $id)->get()->toJson(JSON_PRETTY_PRINT);
        return response($student, 200);
      } else {
        return response()->json([
          "message" => "Student not found"
        ], 404);
      }
    }

    public function updateStudent(Request $request, $id) {
      if (Student::where('id', $id)->exists()) {
        $student = Student::find($id);

        $student->name = is_null($request->name) ? $student->name : $request->name;
        $student->course = is_null($request->course) ? $student->course : $request->course;
        $student->save();

        return response()->json([
          "message" => "records updated successfully"
        ], 200);
      } else {
        return response()->json([
          "message" => "Student not found"
        ], 404);
      }
    }

    public function deleteStudent ($id) {
      if(Student::where('id', $id)->exists()) {
        $student = Student::find($id);
        $student->delete();

        return response()->json([
          "message" => "records deleted"
        ], 202);
      } else {
        return response()->json([
          "message" => "Student not found"
        ], 404);
      }
    }
}

routes\web.php

<?php

use Illuminate\Http\Request;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});


Route::get('students', 'ApiController@getAllStudents');
Route::get('students/{id}', 'ApiController@getStudent');
Route::post('students, 'ApiController@createStudent');
Route::put('students/{id}', 'ApiController@updateStudent');
Route::delete('students/{id}', 'ApiController@deleteStudent');

app\Student.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Student extends Model
{
    protected $table = 'students';

    protected $fillable = ['name', 'course'];
}

Conseguimos criar uma API RESTful CRUD simples usando o Laravel. Este artigo abordou os fundamentos do assunto. Ele não cobriu a validação de solicitações e a segurança da API, o que seria um excelente próximo passo para você implementar.

Este artigo foi traduzido do original "Building and Consuming a RESTful API in Laravel PHP". Enquanto melhoramos nossos processos de tradução, adoraríamos receber seus comentários em help@twilio.com - contribuições valiosas podem render brindes da Twilio.