ASP.NET Core WebApi - Hello World
📽 Veja esta vídeo-aula no Youtube
📽 Veja também esta live com o mesmo conteúdo e uma abordagem diferenciada
Para criarmos nossa primeira API de backend usaremos o framework ASP.NET Core. Ele usa o conceito orientado a objetos na arquitetura MVC, que se baseia em 3 pilares: Model, View e Controller, onde:
- Model: as classes que representam a estrutura dos dados da aplicação;
- View: a interface da aplicação, visível ao usuário;
- Controller: a lógica da aplicação, que manipula os Models e repassa os dados para as Views.
Vamos usar o template webapi
para iniciar nosso projeto, e depois personalizá-lo.
Usando o template inicial
Crie o projeto usando o template webapi
, assim como você usaria console
.
dotnet new webapi
Serão criados vários arquivos, entre eles:
Program.cs
- arquivo inicial da aplicação, que iniciará um servidor HTTP para responder às requisições.Startup.cs
- ponto inicial do servidor HTTP, onde podemos configurar suas funcionalidades.
Há também uma API de exemplo, que retorna uma lista aleatória de previsões do tempo fake, somente para teste da aplicação. Vamos usá-la para ver se nossa aplicação está rodando.
Execute o projeto normalmente, usando dotnet run
. A saída deve ser algo do tipo:
info: Microsoft.Hosting.Lifetime[0]
Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: C:\caminho\do\projeto\nomeDoProjeto
Atente-se às informações:
Now listening on: https://localhost:5001
: a aplicação está ouvindo a porta5001
, usandohttps
.Now listening on: http://localhost:5000
: a aplicação está ouvindo a porta5000
, usandohttp
.Application started. Press Ctrl+C to shut down.
: a aplicação vai ficar rodando até que você a interrompa usandoCtrl+C
.
Vá até o navegador e acesse https://localhost:5001
e http://localhost:5000
. Você não achará nenhum conteúdo, já que nada está sendo entregue para a raíz do site. Porém, há conteúdo sendo servido pela controller WeatherForecast
. Ela responde à rota /WeatherForecast
com um arranjo JSON contendo o seu resultado. Para vê-lo, então, precisamos acessar https://localhost:5001/WeatherForecast
ou http://localhost:5000/WeatherForecast
.
Perceba que você não conseguirá acessar nenhum deles, devido à configuração de segurança. Podemos simplesmente aceitar o acesso ao site inseguro, ou desabilitar o redirecionamento automático para HTTPS, comentando a linha abaixo em Startup.cs
:
// app.UseHttpsRedirection();
Pare o servidor e o inicie novamente. Agora você conseguirá acessar a versão sem HTTPS, em http://localhost:5000/WeatherForecast
, e verá algo como:
[
{
"date": "2020-10-27T12:31:50.0427198-03:00",
"temperatureC": 1,
"temperatureF": 33,
"summary": "Freezing"
},
{
"date": "2020-10-28T12:31:50.0427449-03:00",
"temperatureC": 46,
"temperatureF": 114,
"summary": "Scorching"
},
{
"date": "2020-10-29T12:31:50.042746-03:00",
"temperatureC": 30,
"temperatureF": 85,
"summary": "Hot"
},
{
"date": "2020-10-30T12:31:50.0427462-03:00",
"temperatureC": 24,
"temperatureF": 75,
"summary": "Cool"
},
{
"date": "2020-10-31T12:31:50.0427468-03:00",
"temperatureC": 7,
"temperatureF": 44,
"summary": "Bracing"
}
]
Para habilitar HTTPS, precisamos da maiores configurações, o que não é o foco agora.
🐱👤 Você também pode acessar a listagem de todos os endpoints disponíveis e sua documentação a partir da url /swagger
.
Criando uma controller simples
Vamos criar uma controller que responda à rota /HelloWorld
e nos retorne um objeto JSON { mensagem: "Hello Dev Web!" }
.
Primeiro vamos excluir os arquivos do exemplo WeatherForecast
. Exclua a model WeatherForecast.cs
, e a controller Controllers\WeatherForecastController.cs
.
Não vamos criar um model, porque nosso resultado é muito simples. Vamos direto para a controller. Crie na pasta Controllers
um arquivo com o nome da rota desejada, mais a palavra Controller
, e a extensão .cs
. No caso, utilize Controllers\HelloWorldController.cs
. Seu conteúdo:
using System;
using Microsoft.AspNetCore.Mvc;
namespace nomeDoProjeto.Controllers
{
[ApiController]
[Route("[controller]")]
public class HelloWorldController : ControllerBase
{
[HttpGet]
public Object Get()
{
return new { mensagem = "Hello Dev Web!" };
}
}
}
Linha a linha:
namespace nomeDoProjeto.Controllers
indica o nome que usaremos para referenciar nossa controller.public class HelloWorldController : ControllerBase
cria uma classe chamadaHelloWorldController
, que herda todas as características deControllerBase
. Faça isso sempre que sua classe for uma controller de API. Exige referência aMicrosoft.AspNetCore.Mvc
.[ApiController]
marca a classe como uma controller de API, e garante que ela saberá receber e responder requisições HTTP.[Route("[controller]")]
indica a rota a ser respondida, no caso, o nome da controller (/HelloWorld
).public Object Get()
cria um método como nomeGet
, sem argumentos, que retorna um objeto. Usar a classeObject
exige referência aSystem
.[HttpGet]
indica que o método responderá a chamadas HTTP feitas com o verbo GET, que é o verbo usado em chamadas de navegador usando URL, e também a chamada padrão da Fetch API.new { mensagem = "Hello Dev Web!" }
cria um objeto sem classe definida (ou seja, do tipoObject
), contento uma única propriedade,mensagem
, com o valor que queremos retornar.
Ao rodar esse programa, a aplicação passa a escutar http://localhost:5000/HelloWorld
, e retornar o JSON abaixo:
{
"mensagem": "Hello Dev Web!"
}
Nosso backend está funcional.
Frontend integrada
Podemos acessar essa API usando Fetch. Para isso, vamos colocar arquivos HTML, CSS e JavaScript em nossa aplicação.
Primeiro, precisamos ativar o recurso que entrega arquivos estáticos. Adicione as linhas em Startup.cs
, antes de app.UseRouting()
:
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseStaticFiles()
indica que a aplicação deve entregar, além dos endpoints, arquivos estáticos. Eles deverão estar em/wwwroot
.app.UseStaticFiles()
indica que a aplicação deve entregar arquivos padrão (comoindex.html
) quando o nome de arquivo não for indicado.
Agora, crie a pasta /wwwroot
, e nele coloque sua aplicação. Por exemplo:
Marcação:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello Dev Web</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<img src="imagens/logo.png" alt="Dev Web">
<h1>Temos uma mensagem para você:</h1>
<div id="mensagem"></div>
<script src="index.js"></script>
</body>
</html>
Estilização
body {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
}
body > * {
flex: 1;
}
#mensagem {
color: #004545;
font-size: 2em;
}
Script:
const iniciar = async () => {
const mensagem = document.getElementById("mensagem");
const response = await fetch('/HelloWorld');
const result = await response.json();
mensagem.innerHTML = result.mensagem;
};
document.addEventListener('DOMContentLoaded', iniciar);
Você terá uma estrutura assim:
Ao acessar, você verá algo do tipo:
Retornando um objeto complexo
Digamos que gostaríamos de retornar um objeto com uma estrutura mais complexa, por exemplo, uma mensagem um link para o Dev Web.
O ideal é criar uma classe que especifique esse formato explicitamente. Normalmente a chamamos de DTO, ou Data Transfer Object. Vamos criar então uma model chamada HelloWorldModel
, em /Models
, com essa finalidade.
namespace nomeDoProjeto.Models
{
public class HelloWorldModel
{
public string mensagem { get; set; }
public string url { get; set; }
}
}
Agora, vamos alterar a controller
para retornar um objeto desse tipo.
using Microsoft.AspNetCore.Mvc;
using nomeDoProjeto.Models; // referência às models
namespace nomeDoProjeto.Controllers
{
[ApiController]
[Route("[controller]")]
public class HelloWorldController : ControllerBase
{
[HttpGet]
public HelloWorldModel Get() // o retorno é uma model
{
// Cria uma instância de HelloWorldModel, e a retorna
var resultado = new HelloWorldModel
{
mensagem = "Hello Dev Web!",
url = "https://github.com/ermogenes/aulas-programacao-web/"
};
return resultado;
}
}
}
O resultado passa a ser:
{
"mensagem": "Hello Dev Web!",
"url": "https://github.com/ermogenes/aulas-programacao-web/"
}
E podemos alterar o script para considerar o link.
mensagem.innerHTML = `<a href="${result.url}">${result.mensagem}</a>`;