Skip to content

Capítulo 2: Aplicação OCI PIZZA

2.4 APIs RESTful

2.4.1 O que é uma API?

A API (Application Programming Interface), ou Interface de Programação de Aplicativos, é um conjunto de regras e protocolos que possibilita a comunicação e a troca de dados entre diferentes aplicações, mesmo quando desenvolvidas usando diferentes tecnologias.

NOTA

Nem toda API é uma API web, e existem diversas variações que utilizam diferentes protocolos e tecnologias, como SOAP (Simple Object Access Protocol), APIs que realizam chamadas de procedimento remoto (RPC - Remote Procedure Calls), entre outras. Nesta seção, o foco será explicar as APIs web que utilizam o protocolo HTTP e que seguem os princípios do REST.

Duas palavras-chave que ajudam a definir o papel das APIs são:

  • Conjunto de Regras

    • Está relacionado ao contrato de comunicação da API, ou sua interface, que define basicamente detalhes como os endpoints utilizados na comunicação, o formato das requisições e respostas, os tipos de dados e as informações sobre autenticação. Esse contrato é indispensável para os desenvolvedores, pois fornece uma especificação clara que facilita a compreensão de como a API deve ser utilizada.
  • Protocolo

    • Os computadores utilizam protocolos para se comunicar. Um protocolo é um conjunto de regras que deve ser seguido para que a troca de informações ocorra. No caso da aplicação OCI PIZZA, as funcionalidades disponíveis por meio das APIs utilizam o protocolo HTTP.

APIs são utilizadas para expor uma ou mais funcionalidades de uma aplicação, permitindo que essas funcionalidades sejam acessadas por outras aplicações por meio de uma interface simples, ao mesmo tempo em que ocultam os detalhes complexos da implementação.

Uma outra forma de entender o que é uma API é considerar que nós, humanos, dependemos de interfaces gráficas para interagir e trocar dados com as aplicações que usamos, enquanto as próprias aplicações utilizam APIs para facilitar a troca de informações entre si.

Atualmente, muitas aplicações web são desenvolvidas usando o conceito API First, o que permite a separação entre as camadas de frontend e backend. Isso significa que é possível, por exemplo, criar uma interface gráfica utilizando HTML, CSS e JavaScript, e uma aplicação móvel nativa para Android desenvolvida em Java ou Kotlin, onde ambas utilizam o mesmo conjunto de APIs do backend.

Por fim, as APIs facilitam a integração entre diferentes sistemas e, no caso da aplicação OCI PIZZA, uma plataforma como o iFood pode utilizar suas APIs para permitir que os usuários façam pedidos diretamente pelo aplicativo do iFood, sem a necessidade de acessar a interface web da aplicação OCI PIZZA.

alt_text

2.4.2 Recursos e Representações

Recursos são os elementos fundamentais dos sistemas web, a ponto de as aplicações web serem frequentemente classificadas como "aplicações orientadas a recursos"1. Um recurso pode ser qualquer item disponibilizado por um servidor web, como um documento HTML, um documento PDF, um vídeo, um processo de negócio, um dispositivo, entre outros.

Um recurso pode ser entendido como sendo a representação de um elemento do mundo real dentro de um contexto computacional. Exemplos de recursos da aplicação OCI PIZZA incluem: Pizza, Pessoa ou Pedido.

Recursos que são disponibilizados por um servidor web possuem uma ou mais formas de representações. O recurso Pizza dentro do contexto da aplicação OCI PIZZA, é representado da seguinte forma:

$ curl https://api.ocipizza.com.br/pizzas/5
{
  "data": {
    "description": "presunto coberto com mussarela, milho, ervilha, palmito, ovo e cebola.",
    "id": 5,
    "image": "https://objectstorage.sa-saopaulo-1.oraclecloud.com/n/we1rxz34/b/pizza-img/o/pizza-portuguesa.jpg",
    "name": "portuguesa",
    "price": "54.99"
  },
  "message": "null",
  "status": "success"
}

Pizza é, na verdade, um objeto que possui algumas propriedades que o descrevem. No exemplo acima, uma Pizza é representada através de um documento do tipo JSON. No entanto, nada impede que esse objeto seja representado também em formatos como XML ou HTML, por exemplo. A escolha do formato dependerá de como você decide implementar as representações dos seus recursos.

Os recursos representados pela aplicação OCI PIZZA seguem a especificação JSend, que estabelece diretrizes sobre como as respostas JSON devem ser formatadas. O JSend é fácil de implementar e proporciona um formato que considero elegante e de fácil interpretação para as aplicações consumidoras.

Toda resposta de uma aplicação que segue a especificação JSend inclui os seguintes campos:

  • data

    • Campo que contém os dados da resposta à solicitação. Este campo pode incluir uma lista de objetos, um único objeto ou o valor null, que indica a ausência de dados.
  • status

    • success: indica que a solicitação foi processada com êxito.
    • fail: indica uma falha no processamento da solicitação, geralmente relacionada a dados inválidos fornecidos pelo cliente.
    • error: indica uma exceção que impede o servidor de processar a solicitação.
  • message

    • Mensagem descritiva que indica o motivo da falha, seja ela do tipo fail ou error. No caso de success, o campo status geralmente é null, indicando a ausência de uma mensagem.

Por exemplo, ao tentar recuperar um CEP inválido da aplicação OCI PIZZA, obtemos o seguinte erro:

1
2
3
4
5
6
$ curl http://api.ocipizza.com.br/locations/zipcodes/0395381
{
  "data": "null",
  "message": "Cannot find state and city from zipcode.",
  "status": "fail"
}

NOTA

Consulte o link JSend para mais informações sobre essa especificação.

2.4.3 REST

Agora que entendemos o que é uma API, bem como os conceitos sobre recursos e representações, podemos avançar para compreender o que é REST.

Definido por Roy Thomas Fielding em sua tese de Ph.D., REST, que significa REpresentational State Transfer (Transferência de Estado Representacional), não é uma tecnologia e não é um protocolo, mas sim um estilo arquitetural que orienta o design de APIs para serviços web modernos (web services). Uma API que segue as especificações desse estilo arquitetural é chamada de REST API.

NOTA

Um web service é considerado RESTful quando todas as suas APIs estão em conformidade com os princípios e restrições REST.

O significado de cada palavra do acrônimo REST é detalhado a seguir:

  • Transferência

    • Refere-se ao processo de enviar e receber as representações dos recursos através da rede. Essa transferência ocorre por meio de chamadas que utilizam o protocolo HTTP.
  • Estado

    • Refere-se a condição atual do recurso naquele instante de tempo. Quando um cliente interage com um recurso, ele pode, desde que tenha a devida autorização, modificar seu estado (por exemplo, atualizar o valor da Pizza).
  • Representacional

    • Refere-se à forma como um recurso é apresentado ou representado para o mundo externo. Por exemplo, o recurso Pizza pode ser representado por meio de um documento JSON.

REST define seis características arquiteturais que devem ser seguidas na construção de APIs. Essas características são essenciais para que uma API seja considerada "verdadeiramente RESTful". Sistemas que incorporam todos esses princípios são classificados como RESTful, exceto pela sexta característica, que é opcional.

As seis características são:

  • 1. Client-Server (cliente-servidor)

    • Servidores e clientes podem ser desenvolvidos ou substituídos de forma independente, sem qualquer dependência entre si. Isso significa que tanto o cliente quanto o servidor têm suas próprias responsabilidades. Por exemplo, o servidor pode "comunicar-se" com o cliente sem se preocupar com a experiência do usuário. O cliente, por sua vez, precisa conhecer apenas as URIs dos recursos disponibilizados pelo servidor.
  • 2. Stateless (sem estado)

    • O HTTP é um protocolo que funciona com um modelo de requisição e resposta. Isso significa que o cliente envia uma requisição e o servidor responde com base nessa solicitação. O REST estabelece que o ciclo de requisição/resposta deve ser autônomo, ou seja, uma resposta não deve depender de informações previamente armazenadas pelo cliente. Em outras palavras, cada requisição deve ser tratada como uma nova solicitação, sem histórico, e o servidor não precisa e nem deve reter nenhuma informação do cliente para concluir o ciclo de requisição/resposta.
  • 3. Cacheable (cache)

    • Em REST, o cache deve ser aplicado apenas aos recursos que explicitamente indicam que podem ser armazenados em cache. Por exemplo, respostas que contenham instruções no cabeçalho HTTP como Cache-Control: public, max-age=86400, indicam que essas respostas podem ser armazenadas em cache pelo cliente. Usar cache melhora o desempenho, pois os dados armazenados em cache podem ser acessados mais rapidamente do que ao consultar um servidor remoto.
  • 4. Uniform interface (interface uniforme)

    • Pode ser considerado um dos aspectos mais importantes, pois estabelece o contrato entre cliente e servidor. O termo "contrato" refere-se à interface da API que você cria para seus recursos, bem como à forma padronizada que os dados devem assumir. Todos os recursos expostos devem ser manipuláveis e acessíveis exclusivamente por meio dos métodos conhecidos do protocolo HTTP (GET, POST, PUT, etc.). Além disso, é fundamental que os recursos expostos sigam algumas boas práticas relacionadas à nomenclatura, formatos de URL e formatos de dados, como HTML, XML e/ou JSON.
  • 5. Layered system (sistema em camadas)

    • O REST possibilita a implementação de uma arquitetura em camadas, onde as APIs podem ser hospedadas em um servidor A, os dados armazenados em um servidor B e a autenticação das solicitações realizada por um servidor C, por exemplo. Geralmente, o cliente não consegue identificar se está se comunicando diretamente com o servidor final ou se está passando por um intermediário durante o processo.
  • 6. Code on demand (código sob demanda)

    • Essa é uma restrição opcional que permite ao servidor enviar trechos de código para o cliente executar. Essa ideia se torna mais clara quando consideramos o funcionamento dos Applets Java, onde um código ou uma pequena aplicação desenvolvida em Java, chamada de Applet, é transmitida do servidor para o cliente executar.

2.4.4 APIs da aplicação OCI PIZZA

Toda a lógica da aplicação foi organizada em diferentes módulos, cada um responsável por uma funcionalidade específica. Por exemplo, o módulo pizza não apenas exibe o cardápio de pizzas, mas também permite a manipulação de suas informações.

NOTA

Um módulo é um diretório que contém arquivos Python. Dividir uma aplicação em módulos é uma prática recomendada que melhora a organização, a manutenção e a escalabilidade do código.

Os módulos da aplicação OCI PIZZA são organizados por meio de Blueprints. Um Blueprints, em Flask, é uma maneira de organizar uma aplicação em componentes menores como se fossem mini-aplicações.

NOTA

Consulte "Modular Applications with Blueprints" para obter mais informações sobre Blueprints em Flask.

Na aplicação OCI PIZZA, cada módulo é organizado em duas partes principais:

  • HTML Views

    • Contém o código que é responsável por gerar o conteúdo HTML para os usuários. Toda a lógica das HTML Views está centralizada no arquivo views.py de cada módulo.
  • API REST

    • Contém o código que expõe as APIs REST do módulo. A lógica relacionada às APIs REST estão contidas no arquivo api.py de cada módulo.

alt_text

APIs REST

REST especifica algumas boas práticas utilizando os mecanismos do HTTP para construção de APIs, como por exemplo, CRUD APIs que especificam como os clientes podem realizar operações de criação, leitura, atualização e exclusão utilizando os verbos HTTP:

CRUD Verbo HTTP Descrição
C (Create) POST Cria um novo recurso.
R (Read) GET Recupera os dados de um recurso existente.
U (Update) PUT,PATCH Atualiza os dados de um recurso existente.
D (Delete) DELETE Remove um recurso.

NOTA

Há uma diferença entre PUT e PATCH onde o verbo PUT é utilizado para substituír o recurso por completo com novos valores. Já o verbo PATCH é usado para atualizar propriedades individuais de um recurso.

Pizza

Método Endpoint Descrição Protegido
GET /pizzas Lista todas as pizzas Não
GET /pizzas/{pizza_id} Obtém os detalhes de uma pizza específica Não
POST /pizzas Adiciona uma nova pizza Sim (Admin)
PUT /pizzas/{pizza_id} Atualiza informações de uma pizza Sim (Admin)
DELETE /pizzas/{pizza_id} Remove uma pizza Sim (Admin)

Order

Método Endpoint Descrição Protegido
GET /orders Lista todos os pedidos Sim (Admin)
GET /orders/users/{user_id} Lista todos os pedidos associado a um usuário específico Sim
GET /orders/{order_id}/users/{user_id} Obtém os detalhes de um pedido associado a um usuário específico Sim
GET /orders/{order_id} Obtém os detalhes de um pedido específico Sim
POST /orders/users/{user_id} Criar um novo pedido associado a um usuário específico Sim
PUT /orders/users/{user_id} Atualiza as informações de um pedido de um usuário específico Sim
DELETE /orders/{order_id} Remove um pedido Sim (Admin)

User

Método Endpoint Descrição Protegido
GET /users Lista todos os usuários Sim (Admin)
GET /users/{user_id} Obtém os detalhes de um usuário específico Sim
POST /users Criar um novo usuário Não
PUT /users/{user_id} Atualiza as informações de um usuário específico Sim
DELETE /users/{user_id} Remove um usuário Sim (Admin)
POST /users/login Autentica um usuário e faz login Não
POST /users/logout Faz logout do usuário autenticado Não

Location

Método Endpoint Descrição Protegido
GET /api/locations Lista todos os Estados e Cidades Sim (Admin)
GET /api/locations/{zipcode} Obtém o Estado e a Cidade através do código postal Sim
POST /api/locations Cria um Estado e Cidade Sim (Admin)
PUT /api/locations/{location_id} Atualiza as informações de um Estado e Cidade Sim (Admin)
DELETE /api/locations/{location_id} Remove um Estado e Cidade Sim (Admin)