Como implantar um aplicativo Deno?
Existem várias opções de implementação para aplicativos da Web criados com o Deno. No entanto, a conteinerização como plataforma de serviço tornou-se uma escolha popular nos últimos tempos devido às várias vantagens que oferece em relação a outras opções de implementação.
Neste artigo, você explorará o Deno, suas vantagens e suas limitações. Além disso, você criará um aplicativo Deno simples e o implantará em contêineres Back4app.
Contents
O que é Deno?
O Deno é um tempo de execução seguro e moderno para JavaScript e TypeScript, criado para abordar as limitações e as falhas de design encontradas no Node.js.
Ao contrário do Node.js, ele enfatiza a segurança por padrão, impondo permissões granulares para o sistema de arquivos e o acesso à rede.
Além disso, o Deno oferece suporte nativo ao TypeScript, eliminando a necessidade de etapas adicionais de configuração ou transpilação, entre outros recursos.
Desde seu lançamento em 2018, o Deno tem atraído a atenção e o interesse dos desenvolvedores devido a seus aprimoramentos em relação ao Node.js.
No entanto, embora o Deno ofereça melhorias, o Node.js continua sendo um ecossistema maduro com amplo suporte da comunidade e um vasto repositório de pacotes.
Apesar disso, a Deno atraiu uma comunidade crescente de desenvolvedores que apreciam sua abordagem e estão explorando seu potencial.
Vantagens do Deno
O aumento da popularidade da Deno se deve a alguns motivos subjacentes. Alguns deles são os seguintes.
Segurança aprimorada em relação ao Node.js
A Deno oferece segurança aprimorada como uma das principais vantagens, implementando um modelo de segurança baseado em permissões e executando aplicativos em um ambiente de sandbox.
Ele implementa um modelo de segurança baseado em permissões, em que é necessária uma autorização explícita para acessar recursos como o sistema de arquivos e a rede.
Por padrão, o Deno opera em um modo restrito e executa aplicativos em um ambiente de sandbox, limitando ações potencialmente arriscadas, isolando-as do sistema subjacente e impedindo o acesso direto a recursos confidenciais.
Auditorias de segurança abrangentes e revisões meticulosas de código reforçam ainda mais a segurança robusta do Deno. Essas medidas proporcionam uma plataforma confiável e segura para a criação de aplicativos, inspirando confiança em sua segurança e protegendo contra possíveis vulnerabilidades.
Gerenciamento de dependências
O Deno oferece uma abordagem distinta para o gerenciamento de dependências em comparação com os ambientes tradicionais de tempo de execução do JavaScript, como o Node.js.
Em vez de depender de um registro de pacotes centralizado, o Deno utiliza URLs para importar módulos diretamente da Web.
Essa abordagem simplifica o processo, eliminando a necessidade de um gerenciador de pacotes separado, como o npm, e atenuando as preocupações relacionadas a conflitos de versão e as complexidades do gerenciamento da pasta “node_modules”.
Você pode especificar as dependências especificando os URLs dos módulos que deseja importar, facilitando o compartilhamento e a distribuição do código. Essa abordagem descentralizada do gerenciamento de dependências no Deno promove a simplicidade, reduz o atrito e ajuda a garantir uma experiência de desenvolvimento mais otimizada.
Suporte a TypeScript pronto para uso
O Deno oferece suporte nativo e contínuo ao TypeScript, o que o torna uma excelente opção se você preferir ou precisar do TypeScript em seus projetos.
O TypeScript é um superconjunto tipado de JavaScript que traz tipagem estática e outros recursos avançados de linguagem para o desenvolvimento de JavaScript. Com o Deno, não há necessidade de configuração adicional ou etapas de compilação para usar o TypeScript.
O Deno é fornecido com o compilador TypeScript, permitindo que você escreva e execute o código TypeScript diretamente.
Esse suporte nativo elimina as complexidades da configuração de uma cadeia de ferramentas TypeScript separada e simplifica o processo de desenvolvimento.
Ele permite que você aproveite a verificação de tipos do TypeScript, as ferramentas aprimoradas e a experiência aprimorada do desenvolvedor ao criar aplicativos com o Deno.
Limitações do Deno
No entanto, o Deno tem certas limitações que estão afetando sua adoção. Algumas delas são as seguintes.
Ecossistema imaturo
Uma das limitações do Deno é a maturidade de seu ecossistema. Em comparação com o Node.js, que existe há mais tempo, o ecossistema do Deno ainda é relativamente novo e está evoluindo.
Isso significa que pode haver menos bibliotecas, estruturas e ferramentas de terceiros projetadas especificamente para o Deno. Talvez seja necessário criar determinadas funcionalidades do zero ou adaptar pacotes Node.js existentes para uso no Deno.
O tamanho menor da comunidade também significa que pode haver menos recursos, tutoriais e suporte da comunidade disponíveis em comparação com o ecossistema bem estabelecido do Node.js.
No entanto, à medida que o Deno ganha popularidade e adoção, espera-se que seu ecossistema cresça e amadureça, oferecendo uma gama mais ampla de bibliotecas e ferramentas no futuro.
Curva de aprendizado acentuada
Outra limitação do Deno é a curva de aprendizado associada à transição de outros ambientes de tempo de execução de JavaScript, como o Node.js.
O Deno apresenta novos conceitos, APIs e padrões com os quais você talvez precise se familiarizar. Isso inclui entender o sistema de módulos do Deno, o modelo de segurança baseado em permissões e as diferenças na forma como determinadas funcionalidades são implementadas em comparação com outros tempos de execução.
Os desenvolvedores que já são proficientes em Node.js podem precisar investir tempo e esforço para aprender e se adaptar aos recursos e convenções específicos do Deno.
No entanto, a curva de aprendizado pode ser gerenciada consultando a documentação oficial do Deno, interagindo com a comunidade Deno e explorando os recursos de aprendizado disponíveis.
Compatibilidade com bibliotecas Node.js
A compatibilidade com as bibliotecas do Node.js é outra limitação do Deno. Devido às diferenças nos sistemas de módulos e ambientes de tempo de execução, nem todas as bibliotecas e módulos do Node.js podem ser usados diretamente no Deno sem modificações.
O Deno usa módulos ES (módulos ECMAScript) como seu sistema de módulos, enquanto o Node.js tradicionalmente usa módulos CommonJS. Essa diferença nos formatos de módulo pode levar a incompatibilidades ao importar e usar módulos específicos do Node.js no Deno.
Os desenvolvedores podem precisar fazer ajustes ou encontrar bibliotecas alternativas que sejam especificamente projetadas para funcionar com o sistema de módulos da Deno.
Embora o Deno forneça uma camada de compatibilidade para executar alguns módulos do Node.js, ele pode não abranger todos os casos, e podem ser necessárias modificações ou adaptações manuais.
Opções de implantação do Deno
Há várias opções de implantação para os aplicativos Deno, e algumas delas incluem as seguintes.
Infraestrutura como serviço (IaaS)
A infraestrutura como serviço (IaaS) é um modelo de computação em nuvem que oferece recursos de computação virtualizados. Com a IaaS, você pode alugar máquinas virtuais, armazenamento e rede de provedores de nuvem com base no pagamento conforme o uso. Isso permite que você configure e gerencie sua própria infraestrutura virtualizada sem investir em hardware físico.
As opções de IaaS permitem que você execute aplicativos Deno em máquinas virtuais. Plataformas populares de IaaS, como AWS, Google Cloud e Microsoft Azure, oferecem soluções flexíveis e dimensionáveis, permitindo que você configure a infraestrutura de acordo com as necessidades específicas do seu aplicativo.
No entanto, embora a IaaS ofereça maior controle e isolamento de recursos, ela também exige configuração e gerenciamento mais manuais, envolvendo tarefas como provisionamento de servidores, atualizações de segurança e monitoramento.
Portanto, a IaaS é uma opção viável quando você precisa de amplo controle sobre sua infraestrutura e tem a experiência necessária para lidar com suas complexidades de forma eficaz.
Contêiner como serviço (CaaS)
O Container-as-a-Service (CaaS) é um modelo de computação em nuvem que simplifica a implantação e o gerenciamento de aplicativos em contêineres.
Com o CaaS, você pode se concentrar na criação e na implementação de aplicativos sem se preocupar com a infraestrutura subjacente.
Os aplicativos da Deno podem ser implantados em contêineres, garantindo consistência e isolamento. Os contêineres do Back4app são uma opção popular de CaaS para a implantação do Deno.
As plataformas de CaaS oferecem escalabilidade e isolamento de recursos, com cada aplicativo sendo executado em seu próprio contêiner, o que aumenta a segurança e a estabilidade.
A consistência dos contêineres garante que os aplicativos Deno possam ser facilmente implantados em qualquer plataforma que ofereça suporte a contêineres.
Embora as soluções de CaaS tenham uma curva de aprendizado, elas oferecem benefícios significativos para aplicativos que exigem dimensionamento e implementação dinâmicos em vários nós ou clusters.
Processo de instalação do Deno
Antes de usar o Deno, é necessário fazer o download e instalá-lo. A instalação do Deno varia de acordo com seu sistema operacional.
No macOS e no Linux, você pode instalar o Deno executando o comando abaixo:
curl -fsSL <https://deno.land/x/install/install.sh> | sh
No Windows, você pode instalar o Deno usando o Powershell, executando o comando abaixo:
irm <https://deno.land/install.ps1> | iex
Para confirmar que a instalação foi bem-sucedida, execute o comando abaixo e ele deverá imprimir um número de versão em seu terminal.
deno --version
Se você não vir o número da versão, tente instalar o Deno novamente.
Configuração de um projeto Deno
Para criar uma API simples com o Deno, você precisará de um roteador, um servidor e um banco de dados.
Antes de seguir as etapas abaixo, crie uma pasta src
no diretório raiz do seu projeto. Essa pasta conterá todos os arquivos de origem de seu projeto.
Etapa 1: Criação de um arquivo de dependência
Ao contrário do Node.js, o Deno não usa gerenciadores de pacotes como o NPM ou o Yarn. Em vez disso, os pacotes são importados diretamente de seu URL.
Para imitar as funções de um arquivo package.json
, crie um deps.ts
no diretório raiz do seu projeto e adicione o bloco de código abaixo a ele.
export { Application, Router } from "https://deno.land/x/[email protected]/mod.ts";
export type { RouterContext} from "https://deno.land/x/[email protected]/mod.ts";
export { config as dotenvConfig } from "https://deno.land/x/[email protected]/mod.ts";
export { Client } from "https://deno.land/x/[email protected]/mod.ts";
O bloco de código acima importa (instala) e exporta Application
, Router
e RouterContex
do Oak. config
do dotenv e Client
do deno-postgres.
Etapa 2: Criação de um servidor
Para esta etapa, você criará um servidor HTTP simples com o Oak. O Oak é um middleware para o servidor HTTP do Deno baseado no Koa.js, uma estrutura para Node.js semelhante ao Express, mas mais leve.
Para criar um servidor HTTP com o Oak, crie um arquivo server.ts
em seu src
e adicione o bloco de código abaixo a ele.
import { Application } from "../deps.ts";
import config from "../config/default.ts";
import router from "./router.ts";
const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: config.port });
O bloco de código acima cria um servidor HTTP com Oak e registra um roteador para lidar com todo o tráfego de entrada.
A linha app.use(router.routes())
registra as rotas do roteador como middleware no aplicativo Oak. Todas as solicitações de entrada serão comparadas com as rotas registradas, e os manipuladores correspondentes serão executados se uma correspondência for encontrada.
Se uma correspondência não for encontrada, a linha app.use(router.allowedMethods())
lida com elas enviando respostas apropriadas, como 404 não encontrado ou 405 não permitido.
Etapa 3: Gerenciamento de variáveis ambientais
O armazenamento de dados confidenciais, como chaves de API, credenciais de banco de dados etc., em texto simples representa um risco de segurança. Qualquer pessoa que tenha acesso às suas chaves ou credenciais pode ter acesso irrestrito ao seu aplicativo. Isso pode resultar em perda e roubo de dados, entre outras possíveis explorações.
É considerada uma boa prática armazenar dados confidenciais em variáveis ambientais para evitar situações como essa.
Crie um arquivo .env
na pasta raiz do seu projeto e armazene as credenciais do banco de dados e outras informações confidenciais nesse arquivo.
Assim:
#.env
DB_URI = <YOUR_POSTGRES_DB_URI>
PORT = 8000
Substitua por suas credenciais de banco de dados.
Em seguida, crie uma pasta config
na pasta raiz do seu projeto e, na pasta config, crie um arquivo default.ts
e adicione o bloco de código abaixo a ele.
//default.ts
import { dotenvConfig } from "../deps.ts";
dotenvConfig({
export: true,
path: "../.env",
});
const config = {
db: {
dbUri: Deno.env.get("DB_URI"),
},
port: 3000
};
export default config;
O bloco de código acima recupera com segurança os valores armazenados em seu arquivo .env
e os expõe ao restante do aplicativo.
Etapa 3: Conexão a um banco de dados
Para esta etapa, você conectará seu aplicativo a um banco de dados Postgres. Você precisará do banco de dados para armazenar e recuperar dados para o seu aplicativo.
Crie um arquivo db.ts
em sua pasta src
e adicione o bloco de código abaixo a ele.
//db.ts
import { Client } from "../deps.ts";
import config from "../config/default.ts";
let postgresConfiguration = config.db.dbUri;
const client = new Client(postgresConfiguration);
await client.connect();
export default client;
O bloco de código acima tenta conectar seu aplicativo a um banco de dados Postgres usando o URI que você forneceu no arquivo .env
.
Etapa 4: Criação de um repositório de banco de dados
Crie um arquivo blogRepository
em sua pasta src
e adicione o código abaixo a esse arquivo.
//blogRepository.ts
import client from "./db.ts";
class BlogRepository {
async createBlogTable() {
const blog = await client.queryArray(
`CREATE TABLE IF NOT EXISTS blogs (id SERIAL PRIMARY KEY, title VARCHAR(255), body VARCHAR(255), author VARCHAR(255))`
);
return blog;
}
async getAllBlogs() {
const allBlogs = await client.queryArray("SELECT * FROM blogs");
return allBlogs;
}
async getBlogById(id: string) {
const blog = await client.queryArray(
`SELECT * FROM blogs WHERE id = ${id}`
);
return blog;
}
async createBlog(title: string, body: string, author: string) {
const blog = await client.queryArray(
`INSERT INTO blogs (title, body, author) VALUES ('${title}', '${body}', '${author}')`
);
return blog;
}
async updateBlog(id: string, title: string, body: string, author: string) {
const blog = await client.queryArray(
`UPDATE blogs SET title = '${title}', body = '${body}', author = '${author}' WHERE id = ${id}`
);
return blog;
}
async deleteBlog(id: string) {
const blog = await client.queryArray(`DELETE FROM blogs WHERE id = ${id}`);
return blog;
}
}
export default new BlogRepository();
O bloco de código acima tratará de todas as operações do banco de dados abstraindo as consultas SQL brutas e expondo métodos simples que você pode usar para interagir com o banco de dados Postgres.
Etapa 5: Criação de manipuladores de rota
Nesta etapa, você criará manipuladores de rota para lidar com funções CRUD simples para o seu aplicativo. As rotas compatíveis são as seguintes:
- GET /api/blogs: Retorna todos os blogs em seu banco de dados
- GET /api/blog/:id: Retorna um único blog com o id correspondente fornecido nos parâmetros de URL.
- POST /api/blog/new: cria um novo blog em seu banco de dados.
- PUT /api/blog/:id: Atualiza um blog com o id correspondente fornecido nos parâmetros do URL.
- DELETE /api/blog/:id: Exclui um blog com o id correspondente fornecido nos parâmetros do URL.
Crie um arquivo router.ts em sua pasta src e adicione as seguintes importações a ele.
import { Router, RouterContext } from "../deps.ts";
import blogRepository from "./blogRepository.ts";
Em seguida, crie uma instância de roteador adicionando o bloco de código abaixo a ela:
const router = new Router();
Para registrar os manipuladores do roteador, é necessário encadeá-los à instância do roteador.
Por exemplo, (GET /api/blogs):
router
.get("/api/blogs", async (ctx: RouterContext<"/api/blogs">) => {
const data = await blogRepository.getAllBlogs();
console.log(data);
//format data
const allBlogs = data.rows.map((blog) => {
return {
id: blog[0],
title: blog[1],
body: blog[2],
author: blog[3]
};
});
ctx.response.body = allBlogs;
})
O bloco de código acima cria um manipulador de rota para GET /api/blogs encadeando a lógica do manipulador à instância do roteador.
Encadeie-os ao método previamente encadeado para registrar o restante das rotas. Assim:
GET /api/blog/:id:
.get("/api/blog/:id", async (ctx: RouterContext<"/api/blog/:id">) => {
try {
const data = await blogRepository.getBlogById(ctx.params.id);
console.log(data);
//format data
const blog = data.rows.map((blog) => {
return {
id: blog[0],
title: blog[1],
body: blog[2],
author: blog[3]
};
});
ctx.response.body = blog;
} catch (error) {
ctx.response.status = 500;
ctx.response.body = {
msg: "Error getting blog",
error,
};
}
})
POST /api/blog/new
.post("/api/blog/new", async (ctx: RouterContext<"/api/blog/new">) => {
const resBody = ctx.request.body();
const blog = await resBody.value;
if (!blog) {
ctx.response.status = 400;
ctx.response.body = { msg: "Invalid data. Please provide a valid blog." };
return;
}
const { title, body, author } = blog;
if (!(title && body && author)) {
ctx.response.status = 400;
ctx.response.body = {
msg: "Title or description missing. Please provide a valid blog.",
};
return;
}
try {
await blogRepository.createBlog(title, body, author);
ctx.response.status = 201;
ctx.response.body = {
msg: "blog added successfully",
};
} catch (error) {
ctx.response.status = 500;
ctx.response.body = {
msg: "Error adding blog",
error,
};
}
})
PUT /api/blog/:id:
.put("/api/blog/:id", async (ctx: RouterContext<"/api/blog/:id">) => {
try {
const resBody = ctx.request.body();
const blog = await resBody.value;
if (!blog) {
ctx.response.status = 400;
ctx.response.body = {
msg: "Invalid data. Please provide a valid blog.",
};
return;
}
const { title, body, author } = blog;
if (!(title && body && author)) {
ctx.response.status = 400;
ctx.response.body = {
msg: "Title or description missing. Please provide a valid blog.",
};
return;
}
await blogRepository.updateBlog(ctx.params.id, title, body, author);
ctx.response.status = 200;
ctx.response.body = {
msg: "blog updated successfully",
};
} catch (error) {
console.log(error);
ctx.response.status = 500;
ctx.response.body = {
msg: "Error updating blog",
error: error.message,
};
}
})
DELETE /api/blog/:id:
.delete("/api/blog/:id", async (ctx: RouterContext<"/api/blog/:id">) => {
await blogRepository.deleteBlog(ctx.params.id);
ctx.response.status = 200;
ctx.response.body = {
msg: "blog deleted successfully",
};
});
Em seguida, exporte a instância do roteador. Assim:
export default router;
Por fim, modifique o arquivo server.ts
para criar um banco de dados de blog quando o aplicativo for iniciado pela primeira vez.
Assim:
import { Application } from "../deps.ts";
import config from "../config/default.ts";
import blogRepository from "./blogRepository.ts";
import router from "./router.ts";
const app = new Application();
(async () => {
await blogRepository.createBlogTable();
})();
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: config.port });
O código modificado adiciona ao arquivo server.ts
um IIFE que cria uma nova tabela de blog em seu banco de dados.
Implantação do seu aplicativo Deno em contêineres Back4app
Para implantar seu aplicativo Deno em contêineres do Back4app, você precisa seguir as etapas abaixo:
Etapa 1: Criar um Dockerfile
Um Dockerfile fornece instruções específicas para a criação de uma imagem do Docker. Essas instruções orientam o processo de criação da imagem.
Execute o comando abaixo para criar um Dockerfile:
touch Dockerfile
O comando acima cria um Dockerfile no diretório raiz do seu projeto.
Em seguida, adicione o bloco de código abaixo ao seu Dockerfile:
FROM denoland/deno:latest
EXPOSE 8000
WORKDIR /app
COPY deps.ts .
RUN deno cache deps.ts
COPY . .
RUN deno cache src/server.ts
CMD ["run", "--allow-net", "--allow-env", "--allow-read", "src/server.ts"]
O Dockerfile acima configura um ambiente em contêiner para executar um aplicativo Deno. Ele armazena em cache as dependências e o ponto de entrada do aplicativo e, em seguida, executa o aplicativo Deno com as permissões especificadas quando o contêiner é iniciado.
Espera-se que o aplicativo escute na porta 8000, embora o mapeamento real da porta deva ser feito ao executar o contêiner.
Por fim, envie seu código para o GitHub.
Etapa 2: Criar um novo aplicativo Back4app
Para criar um aplicativo Back4app, visite o site oficial do Back4app. Uma vez lá, localize o botão Inscrever-se no canto superior direito da página de destino do Back4app. Ao clicar no botão Inscrever-se, você será direcionado a um formulário de registro. Prossiga para preencher esse formulário com os detalhes necessários, como seu endereço de e-mail, nome de usuário e senha. Certifique-se de fornecer informações precisas. Depois de preencher o formulário, envie-o.
Se você já tiver uma conta, clique em Log in.
Depois de configurar com êxito sua conta Back4app, faça login para acessar o painel de controle da sua conta. A partir daí, localize o botão “NEW APP” e clique nele.
Essa ação o direcionará para uma página em que serão apresentadas diferentes opções para criar seu novo aplicativo. Como sua intenção é fazer a implantação usando a conteinerização, opte pela opção“Containers as a Service“.
Em seguida, conecte sua conta do GitHub à sua conta do Back4app. Você pode conceder ao Back4app acesso a todos os repositórios em sua conta ou a repositórios específicos.
Escolha o aplicativo que deseja implantar, neste caso, o aplicativo que você criou neste tutorial, e clique em Select (Selecionar).
Ao clicar no botão Selecionar, você será levado a uma página em que deverá preencher algumas informações sobre o aplicativo, como nome, ramificação, diretório raiz, opções de implantação automática, porta, integridade e variáveis ambientais.
Certifique-se de fornecer todas as variáveis ambientais necessárias para que seu aplicativo funcione corretamente. Depois de concluir o preenchimento das informações necessárias, clique no botão “Create App”.
Isso iniciará o processo de implantação e, após algum tempo, sua implantação deverá estar pronta. Se o processo de implantação estiver demorando muito, você pode verificar os registros para ver se ocorreu algum erro na implantação ou consultar o guia de solução de problemas do Back4app.
Conclusão
Neste artigo, você explorou o Deno, suas vantagens, limitações, opções de implantação populares, como criar um aplicativo com o Deno e implantá-lo usando contêineres do Back4app.
Apesar de suas limitações, devido ao seu modelo de segurança, o Deno pode ser ideal para a criação de aplicativos muito seguros e confidenciais. Além disso, seu suporte nativo ao TypeScript elimina os problemas de configuração do TypeScript em seu projeto.
Seguindo as etapas descritas neste artigo, você pode criar e implantar facilmente seu aplicativo Deno em contêineres do Back4app.
PERGUNTAS FREQUENTES
O que é Deno?
Deno é um tempo de execução JavaScript/TypeScript seguro e moderno que permite aos desenvolvedores criar aplicativos do lado do servidor e do lado do cliente.
Como implantar um aplicativo Deno?
1. Crie um aplicativo Deno
2. Crie um Dockerfile
3. Envie seu aplicativo Deno para o GitHub e conecte sua conta do GitHub à sua conta do Back4app.
4. Crie um aplicativo CaaS no Back4app
5. Selecione seu aplicativo Deno na sua lista de repositórios
6. Implante seu aplicativo Deno