Primeiros Passos com GraphQL e Express: Um Guia Visual e Prático
Construa a sua primeira API GraphQL com Express, passo a passo: schemas, tipos, resolvers, argumentos, dados aninhados, mutações e variáveis, o playground GraphiQL, respostas reais, uma comparação com REST medindo bytes e pedidos, e exercícios com respostas.

Nesta página
Um aplicativo de celular mostra uma lista de frutas com as suas receitas. Com uma API REST clássica, ele chamaria /frutas, depois /frutas/1/receitas, /frutas/2/receitas e assim por diante, e cada resposta traria campos que a tela nunca mostra. O GraphQL inverte isso: o aplicativo manda um pedido descrevendo exatamente os dados que quer, e o servidor responde exatamente nesse formato, nem mais, nem menos.
Neste guia você vai construir uma API GraphQL com Node.js e Express, um passo de cada vez: uma primeira consulta, os seus próprios tipos, argumentos, dados aninhados, mutações e variáveis, além do playground GraphiQL no navegador. Pelo caminho você vai ver cada resposta real, medir o que o GraphQL economiza em comparação com o REST e terminar com exercícios.
Todas as respostas abaixo vêm de execuções reais com Node.js 26, Express 5.3, graphql 16.14, graphql-http 1.23 e Ruru 2.0.
REST vs. GraphQL numa imagem

APIs REST têm muitos endpoints, cada um devolvendo um formato fixo. Isso leva a dois problemas:
- Dados demais (over-fetching): as respostas trazem campos de que o aplicativo não precisa, desperdiçando banda, principalmente em conexões móveis lentas.
- Dados de menos (under-fetching): uma resposta não basta, então o aplicativo faz idas e voltas extras para juntar o resto.
O GraphQL tem um endpoint, normalmente POST /graphql. O cliente manda uma consulta (query) que lista os campos que quer, e um schema no servidor descreve tudo o que pode ser pedido.
Como um pedido GraphQL funciona

Você escreve duas coisas: o schema (o que pode ser pedido, com tipos) e os resolvers (funções que buscam o valor de cada campo). Analisar, validar e montar a resposta fica por conta das bibliotecas.
Preparando tudo
Crie um projeto e instale quatro pacotes:
1mkdir api-de-frutas
2cd api-de-frutas
3npm init -y
4npm install express graphql graphql-http ruru- express: o servidor web.
- graphql: a implementação de referência do GraphQL para JavaScript (schemas, tipos, execução).
- graphql-http: liga o GraphQL ao Express, tratando os pedidos
POST /graphql. - ruru: serve o GraphiQL, o playground no navegador para testar consultas.
O seu primeiro schema
Comece com a menor API possível: um campo, fruta, que sempre responde "Banana". Coloque isto no schema.js:
1// schema.js
2const { GraphQLObjectType, GraphQLSchema, GraphQLString } = require("graphql");
3
4const TipoConsulta = new GraphQLObjectType({
5 name: "Query",
6 fields: {
7 fruta: {
8 type: GraphQLString,
9 resolve() {
10 return "Banana";
11 },
12 },
13 },
14});
15
16module.exports = new GraphQLSchema({ query: TipoConsulta });- O tipo
Queryé a porta de entrada: os campos dele são as coisas que os clientes podem pedir. (Por convenção, ele se chamaQueryem inglês mesmo.) - Cada campo tem um
type(aqui, uma string) e uma funçãoresolveque produz o seu valor.
Agora o servidor, no server.js:
1// server.js
2const express = require("express");
3const { createHandler } = require("graphql-http/lib/use/express");
4const { ruruHTML } = require("ruru/server");
5const schema = require("./schema");
6
7const app = express();
8const PORTA = 3000;
9
10app.all("/graphql", createHandler({ schema }));
11
12app.get("/", (pedido, resposta) => {
13 resposta.type("html");
14 resposta.end(ruruHTML({ endpoint: "/graphql" }));
15});
16
17app.listen(PORTA, () => {
18 console.log(`Servidor GraphQL rodando em http://localhost:${PORTA}/graphql`);
19});O createHandler({ schema }) é toda a integração com o GraphQL: todo pedido para /graphql passa por ele. A segunda rota serve o playground GraphiQL na página inicial (já chegamos lá). Inicie o servidor:
$ node server.js
Servidor GraphQL rodando em http://localhost:3000/graphqlUm pedido GraphQL é um POST HTTP comum com um corpo JSON contendo o texto da consulta. Dá para mandar um com o curl, de um segundo terminal:
$ curl -X POST http://localhost:3000/graphql -H "Content-Type: application/json" -d '{"query": "{ fruta }"}'
{"data":{"fruta":"Banana"}}A consulta { fruta } pede o campo fruta, e a resposta volta dentro de uma chave data, no mesmo formato.
Um cliente pequenininho
Escrever JSON entre aspas na linha de comando cansa rápido (e muda de um terminal para outro), então aqui vai um pequeno cliente Node.js, o perguntar.js, que manda uma consulta e imprime a resposta bem formatada:
1// perguntar.js: manda uma consulta GraphQL para o servidor e imprime a resposta
2async function perguntar(consulta, variaveis) {
3 const resposta = await fetch("http://localhost:3000/graphql", {
4 method: "POST",
5 headers: { "Content-Type": "application/json" },
6 body: JSON.stringify({ query: consulta, variables: variaveis }),
7 });
8 console.log(JSON.stringify(await resposta.json(), null, 2));
9}
10
11perguntar(process.argv[2], process.argv[3] && JSON.parse(process.argv[3]));1$ node perguntar.js "{ fruta }"
2{
3 "data": {
4 "fruta": "Banana"
5 }
6}É exatamente isso que um aplicativo web ou de celular faz por baixo dos panos: um fetch com um POST levando a consulta.
Testando consultas no GraphiQL
Abra http://localhost:3000/ no navegador e você ganha o GraphiQL (servido pelo Ruru): digite uma consulta à esquerda, aperte o botão de play e a resposta aparece à direita. Ele completa os nomes dos campos a partir do seu schema e sublinha os erros enquanto você digita. Aqui ele está rodando uma consulta que aparece mais adiante neste guia:

Criando o seu próprio tipo
Uma string sozinha não é muito interessante. Vamos transformar a fruta num objeto com vários campos, usando um novo GraphQLObjectType:
1// schema.js
2const {
3 GraphQLBoolean,
4 GraphQLID,
5 GraphQLInt,
6 GraphQLObjectType,
7 GraphQLSchema,
8 GraphQLString,
9} = require("graphql");
10
11const TipoFruta = new GraphQLObjectType({
12 name: "Fruta",
13 fields: {
14 id: { type: GraphQLID },
15 nome: { type: GraphQLString },
16 descricao: { type: GraphQLString },
17 ehGostosa: { type: GraphQLBoolean },
18 calorias: { type: GraphQLInt },
19 },
20});
21
22const TipoConsulta = new GraphQLObjectType({
23 name: "Query",
24 fields: {
25 fruta: {
26 type: TipoFruta,
27 resolve() {
28 return {
29 id: "1",
30 nome: "Banana",
31 descricao: "Doce e fácil de descascar",
32 ehGostosa: true,
33 calorias: 89,
34 };
35 },
36 },
37 },
38});
39
40module.exports = new GraphQLSchema({ query: TipoConsulta });Cada campo ganha um dos tipos escalares que vêm com o GraphQL: GraphQLID (um identificador único, sempre enviado como string), GraphQLString, GraphQLBoolean, GraphQLInt e GraphQLFloat para decimais. O tipo do campo fruta agora é o TipoFruta, e o resolver dele devolve um objeto. Os campos não têm resolvers próprios: o resolver padrão do GraphQL simplesmente lê a propriedade de mesmo nome desse objeto.
Reinicie o servidor (pare com Ctrl+C e rode node server.js de novo) e peça todos os campos:
1$ node perguntar.js "{ fruta { id nome descricao ehGostosa calorias } }"
2{
3 "data": {
4 "fruta": {
5 "id": "1",
6 "nome": "Banana",
7 "descricao": "Doce e fácil de descascar",
8 "ehGostosa": true,
9 "calorias": 89
10 }
11 }
12}Agora a parte mágica. Peça só dois campos:
1$ node perguntar.js "{ fruta { id nome } }"
2{
3 "data": {
4 "fruta": {
5 "id": "1",
6 "nome": "Banana"
7 }
8 }
9}
Você recebe exatamente os campos que pediu. Uma página de produto poderia pedir tudo; uma tela de lista poderia pedir só id e nome, da mesma API.
Uma API de verdade: listas, argumentos e dados aninhados
APIs reais servem muitos registros, buscam coisas pelo ID e ligam registros entre si. Vamos guardar os dados num arquivo próprio, fazendo o papel de um banco de dados:
1// dados.js: um "banco de dados" em memória para os exemplos
2const frutas = [
3 { id: "1", nome: "Banana", descricao: "Doce e fácil de descascar", ehGostosa: true, calorias: 89 },
4 { id: "2", nome: "Maçã", descricao: "Crocante e suculenta", ehGostosa: true, calorias: 52 },
5 { id: "3", nome: "Durião", descricao: "Famoso pelo cheiro forte", ehGostosa: false, calorias: 147 },
6];
7
8const receitas = [
9 { frutaId: "1", nome: "Pão de banana", minutos: 70 },
10 { frutaId: "1", nome: "Vitamina de banana", minutos: 5 },
11 { frutaId: "2", nome: "Torta de maçã", minutos: 90 },
12];
13
14module.exports = { frutas, receitas };E o schema completo:
1// schema.js
2const {
3 GraphQLBoolean,
4 GraphQLID,
5 GraphQLInt,
6 GraphQLList,
7 GraphQLNonNull,
8 GraphQLObjectType,
9 GraphQLSchema,
10 GraphQLString,
11} = require("graphql");
12const { frutas, receitas } = require("./dados");
13
14const TipoReceita = new GraphQLObjectType({
15 name: "Receita",
16 fields: {
17 nome: { type: GraphQLString },
18 minutos: { type: GraphQLInt },
19 },
20});
21
22const TipoFruta = new GraphQLObjectType({
23 name: "Fruta",
24 fields: {
25 id: { type: new GraphQLNonNull(GraphQLID) },
26 nome: { type: new GraphQLNonNull(GraphQLString) },
27 descricao: { type: GraphQLString },
28 ehGostosa: { type: GraphQLBoolean },
29 calorias: { type: GraphQLInt },
30 receitas: {
31 type: new GraphQLList(TipoReceita),
32 resolve(fruta) {
33 return receitas.filter((receita) => receita.frutaId === fruta.id);
34 },
35 },
36 },
37});
38
39const TipoConsulta = new GraphQLObjectType({
40 name: "Query",
41 fields: {
42 frutas: {
43 type: new GraphQLList(TipoFruta),
44 resolve() {
45 return frutas;
46 },
47 },
48 fruta: {
49 type: TipoFruta,
50 args: {
51 id: { type: new GraphQLNonNull(GraphQLID) },
52 },
53 resolve(pai, argumentos) {
54 return frutas.find((fruta) => fruta.id === argumentos.id);
55 },
56 },
57 },
58});
59
60const TipoMutacao = new GraphQLObjectType({
61 name: "Mutation",
62 fields: {
63 adicionarFruta: {
64 type: TipoFruta,
65 args: {
66 nome: { type: new GraphQLNonNull(GraphQLString) },
67 calorias: { type: GraphQLInt },
68 },
69 resolve(pai, argumentos) {
70 const fruta = { id: String(frutas.length + 1), nome: argumentos.nome, calorias: argumentos.calorias, ehGostosa: true };
71 frutas.push(fruta);
72 return fruta;
73 },
74 },
75 },
76});
77
78module.exports = new GraphQLSchema({ query: TipoConsulta, mutation: TipoMutacao });As ideias novas, uma por uma:
GraphQLList(TipoFruta)quer dizer "uma lista de frutas".GraphQLNonNull(…)quer dizer "nunca nulo": toda fruta sempre temidenome, e o argumentoidé obrigatório.argsdeclara os argumentos que um campo aceita; o resolver os recebe no segundo parâmetro, aqui chamadoargumentos.- Resolvers aninhados:
receitastem o seu próprio resolver, e o primeiro parâmetro dele é o objeto pai, a fruta sendo resolvida. É assim que o GraphQL caminha de uma fruta até as suas receitas. Mutationguarda os campos que mudam dados (já chegamos lá).
Reinicie o servidor e teste uma lista:
1$ node perguntar.js "{ frutas { nome calorias } }"
2{
3 "data": {
4 "frutas": [
5 {
6 "nome": "Banana",
7 "calorias": 89
8 },
9 {
10 "nome": "Maçã",
11 "calorias": 52
12 },
13 {
14 "nome": "Durião",
15 "calorias": 147
16 }
17 ]
18 }
19}Busque uma fruta pelo ID e as receitas dela no mesmo pedido:
1$ node perguntar.js '{ fruta(id: "1") { nome receitas { nome minutos } } }'
2{
3 "data": {
4 "fruta": {
5 "nome": "Banana",
6 "receitas": [
7 {
8 "nome": "Pão de banana",
9 "minutos": 70
10 },
11 {
12 "nome": "Vitamina de banana",
13 "minutos": 5
14 }
15 ]
16 }
17 }
18}(As aspas simples em volta da consulta impedem que o terminal engula as aspas duplas de dentro. No PowerShell, use aspas simples também.)

O schema na linguagem do próprio GraphQL
O nosso schema é montado com objetos JavaScript, mas o GraphQL tem a sua própria linguagem de definição de schema (SDL, Schema Definition Language), bem compacta, e o pacote graphql consegue imprimir o nosso nela:
1// imprimir-schema.js
2const { printSchema } = require("graphql");
3const schema = require("./schema");
4
5console.log(printSchema(schema));1$ node imprimir-schema.js
2type Query {
3 frutas: [Fruta]
4 fruta(id: ID!): Fruta
5}
6
7type Fruta {
8 id: ID!
9 nome: String!
10 descricao: String
11 ehGostosa: Boolean
12 calorias: Int
13 receitas: [Receita]
14}
15
16type Receita {
17 nome: String
18 minutos: Int
19}
20
21type Mutation {
22 adicionarFruta(nome: String!, calorias: Int): Fruta
23}[Fruta] é uma lista e ! quer dizer não nulo. É essa a notação que você vai ver em toda documentação de GraphQL, e muitas bibliotecas deixam você escrever o schema assim desde o começo.
Quando algo dá errado
O GraphQL confere cada consulta com o schema antes de rodar qualquer resolver. Peça um campo que não existe:
1$ node perguntar.js "{ frutas { nome cor } }"
2{
3 "errors": [
4 {
5 "message": "Cannot query field \"cor\" on type \"Fruta\".",
6 "locations": [
7 {
8 "line": 1,
9 "column": 17
10 }
11 ]
12 }
13 ]
14}("Não é possível consultar o campo cor no tipo Fruta.") Esqueça um argumento obrigatório:
1$ node perguntar.js "{ fruta { nome } }"
2{
3 "errors": [
4 {
5 "message": "Field \"fruta\" argument \"id\" of type \"ID!\" is required, but it was not provided.",
6 "locations": [
7 {
8 "line": 1,
9 "column": 3
10 }
11 ]
12 }
13 ]
14}("O argumento id, do tipo ID!, do campo fruta é obrigatório, mas não foi informado.") A resposta tem uma chave errors em vez de data, com a linha e a coluna do problema. Mas uma pergunta válida sem resposta não é erro: pedir uma fruta que não existe dá null:
1$ node perguntar.js '{ fruta(id: "9") { nome } }'
2{
3 "data": {
4 "fruta": null
5 }
6}Mudando dados: mutações
Consultas leem; mutações (mutations) escrevem. Elas são declaradas no tipo Mutation e chamadas com a palavra-chave mutation. Assim como uma consulta, uma mutação escolhe quais campos do resultado quer de volta:
1$ node perguntar.js 'mutation { adicionarFruta(nome: "Manga", calorias: 60) { id nome calorias } }'
2{
3 "data": {
4 "adicionarFruta": {
5 "id": "4",
6 "nome": "Manga",
7 "calorias": 60
8 }
9 }
10}(O nosso "banco de dados" é um array na memória, então a manga some quando o servidor reinicia. Um resolver de verdade a salvaria num banco de dados.)
Variáveis
Aplicativos de verdade não colam valores no texto da consulta. Eles escrevem a consulta uma vez com variáveis, marcadas com $, e mandam os valores separados, em JSON:
1$ node perguntar.js 'query FrutaPorId($id: ID!) { fruta(id: $id) { nome calorias } }' '{"id": "4"}'
2{
3 "data": {
4 "fruta": {
5 "nome": "Manga",
6 "calorias": 60
7 }
8 }
9}FrutaPorId é o nome da operação (útil nos logs e nas abas do GraphiQL), e $id: ID! declara a variável e o seu tipo. O nosso perguntar.js manda o segundo argumento como as variables do pedido. Manter os valores fora do texto da consulta também é mais seguro, pelo mesmo motivo que você não monta SQL colando strings.
Quanto o GraphQL economiza?
Acrescentamos duas rotas no estilo REST ao mesmo servidor (GET /frutas, devolvendo as frutas completas, e GET /frutas/:id/receitas) e medimos duas telas:

| Tela | Pedidos REST | Bytes REST | Pedidos GraphQL | Bytes GraphQL |
|---|---|---|---|---|
| Nomes das frutas | 1 | 293 | 1 | 76 |
| Nomes das frutas com os nomes das receitas | 4 | 460 | 1 | 199 |
Para a lista de nomes, o GraphQL mandou cerca de um quarto dos bytes. Para os nomes com receitas, o REST precisou de um pedido por fruta além da lista (1 + N, o famoso padrão "N+1"), enquanto o GraphQL precisou de um. Num celular, cada ida e volta extra pode somar dezenas ou centenas de milissegundos, então essa diferença costuma pesar mais que os bytes.
Sua vez: pratique
Tente fazer estes antes de espiar as respostas. Use a API completa da seção "Uma API de verdade", recém-reiniciada.
Exercício 1: Adivinhe a resposta (aquecimento). O que esta consulta devolve?
{ fruta(id: "2") { nome ehGostosa } }Exercício 2: Acrescente um campo. Dê a cada fruta uma cor (amarela, vermelha e verde) e deixe que ela seja consultada, para que { frutas { nome cor } } funcione.
Exercício 3: Uma lista vazia. Escreva uma consulta pedindo as calorias do durião e os nomes das receitas dele. O que você espera em receitas?
Exercício 4: Ache o erro. Por que esta consulta é recusada?
{ frutas }Exercício 5: Filtre com um argumento (desafio). Acrescente um argumento opcional maxCalorias ao campo frutas, para que { frutas(maxCalorias: 100) { nome calorias } } devolva só as frutas com no máximo 100 calorias, enquanto { frutas { nome } } continua devolvendo todas.
Quiz rápido
- Quantos endpoints uma API GraphQL típica tem?
- Qual é a diferença entre o schema e os resolvers?
- O que o
!quer dizer emID!? - Qual é o primeiro parâmetro de um resolver aninhado como o de
receitas? - Quando usar uma mutação em vez de uma consulta?
Respostas
Exercício 1: Só os dois campos pedidos, da fruta com ID 2:
1$ node perguntar.js '{ fruta(id: "2") { nome ehGostosa } }'
2{
3 "data": {
4 "fruta": {
5 "nome": "Maçã",
6 "ehGostosa": true
7 }
8 }
9}Exercício 2: Acrescente o dado no dados.js e uma linha no TipoFruta. O resolver padrão lê a cor direto de cada objeto:
{ id: "1", nome: "Banana", descricao: "Doce e fácil de descascar", ehGostosa: true, calorias: 89, cor: "amarela" },
{ id: "2", nome: "Maçã", descricao: "Crocante e suculenta", ehGostosa: true, calorias: 52, cor: "vermelha" },
{ id: "3", nome: "Durião", descricao: "Famoso pelo cheiro forte", ehGostosa: false, calorias: 147, cor: "verde" }, calorias: { type: GraphQLInt },
cor: { type: GraphQLString },1$ node perguntar.js "{ frutas { nome cor } }"
2{
3 "data": {
4 "frutas": [
5 {
6 "nome": "Banana",
7 "cor": "amarela"
8 },
9 {
10 "nome": "Maçã",
11 "cor": "vermelha"
12 },
13 {
14 "nome": "Durião",
15 "cor": "verde"
16 }
17 ]
18 }
19}Exercício 3: Nenhuma receita tem o ID do durião, então o filter devolve um array vazio, e o GraphQL manda uma lista vazia (não null, e não um erro):
1$ node perguntar.js '{ fruta(id: "3") { nome calorias receitas { nome } } }'
2{
3 "data": {
4 "fruta": {
5 "nome": "Durião",
6 "calorias": 147,
7 "receitas": []
8 }
9 }
10}Exercício 4: frutas é uma lista de objetos, e o GraphQL nunca adivinha quais campos você quer: você tem que listar pelo menos um.
1$ node perguntar.js "{ frutas }"
2{
3 "errors": [
4 {
5 "message": "Field \"frutas\" of type \"[Fruta]\" must have a selection of subfields. Did you mean \"frutas { ... }\"?",
6 "locations": [
7 {
8 "line": 1,
9 "column": 3
10 }
11 ]
12 }
13 ]
14}("O campo frutas, do tipo [Fruta], precisa de uma seleção de subcampos.")
Exercício 5: Declare o argumento sem GraphQLNonNull para ele ser opcional, e só filtre quando ele vier:
1 frutas: {
2 type: new GraphQLList(TipoFruta),
3 args: {
4 maxCalorias: { type: GraphQLInt },
5 },
6 resolve(pai, argumentos) {
7 if (argumentos.maxCalorias === undefined) return frutas;
8 return frutas.filter((fruta) => fruta.calorias <= argumentos.maxCalorias);
9 },
10 },1$ node perguntar.js "{ frutas(maxCalorias: 100) { nome calorias } }"
2{
3 "data": {
4 "frutas": [
5 {
6 "nome": "Banana",
7 "calorias": 89
8 },
9 {
10 "nome": "Maçã",
11 "calorias": 52
12 }
13 ]
14 }
15}1$ node perguntar.js "{ frutas { nome } }"
2{
3 "data": {
4 "frutas": [
5 {
6 "nome": "Banana"
7 },
8 {
9 "nome": "Maçã"
10 },
11 {
12 "nome": "Durião"
13 }
14 ]
15 }
16}Quiz: (1) Um, normalmente /graphql. (2) O schema descreve o que pode ser pedido e os tipos; os resolvers são as funções que produzem o valor de cada campo. (3) Não nulo: o valor sempre está presente (num argumento, quer dizer obrigatório). (4) O objeto pai, aqui a fruta cujas receitas estão sendo resolvidas. (5) Quando a operação muda dados (criar, atualizar ou apagar); consultas só leem.
Cola rápida
| Eu quero… | Escreva |
|---|---|
| Instalar os pacotes | npm install express graphql graphql-http ruru |
| Ligar o GraphQL no Express | app.all("/graphql", createHandler({ schema })) |
| Servir o playground GraphiQL | resposta.end(ruruHTML({ endpoint: "/graphql" })) |
| Definir um tipo de objeto | new GraphQLObjectType({ name: "Fruta", fields: { … } }) |
| Uma lista / um valor obrigatório | new GraphQLList(TipoFruta) / new GraphQLNonNull(GraphQLID) |
| Aceitar argumentos | args: { id: { type: new GraphQLNonNull(GraphQLID) } } |
| Resolver um campo | resolve(pai, argumentos) { return … } |
| Consultar alguns campos | { frutas { nome calorias } } |
| Passar um argumento | { fruta(id: "1") { nome } } |
| Mudar dados | mutation { adicionarFruta(nome: "Manga") { id } } |
| Usar variáveis | query FrutaPorId($id: ID!) { fruta(id: $id) { nome } } mais {"id": "1"} |
| Ver o schema em SDL | printSchema(schema) |
Resumindo
O GraphQL deixa cada cliente pedir exatamente os dados de que precisa, num pedido só:
- Um endpoint, muitos formatos: a consulta do cliente decide quais campos voltam, e a resposta espelha a consulta.
- O schema é o contrato: tipos, listas (
[Fruta]), valores não nulos (!) e argumentos, tudo conferido antes de qualquer coisa rodar. - Os resolvers buscam os dados, campo por campo; resolvers aninhados recebem o objeto pai.
- Mutações mudam dados, e as variáveis deixam os valores fora do texto da consulta.
- O GraphiQL dá autocompletar e documentação ao vivo de graça.
- A economia pode ser grande: nas nossas medições, um quarto dos bytes numa tela de lista, e 1 pedido em vez de 1 + N para dados aninhados.
- Use o
graphql-http, não o obsoletoexpress-graphql.
Novo na linguagem por trás de tudo isso? Leia O Que É a Linguagem de Programação JavaScript?.
Leia a seguir

O Que É a Linguagem de Programação Rust? Um Guia Simples da Linguagem Rápida Que Não Deixa Você Travar
Um guia simples e sem jargões sobre o Rust, a linguagem tão rápida quanto o C que impede famílias inteiras de erros de memória antes de o programa rodar. Entenda a ideia de posse, por que gigantes da tecnologia o adotam e onde ele é usado.

O Que É a Linguagem de Programação Go? Um Guia Simples da Linguagem da Nuvem
Um guia simples e sem jargões sobre o Go, a linguagem simples e rápida que o Google criou para a nuvem. Entenda o que são goroutines, por que um programa Go é um arquivo só e como o Go passou a mover o Docker, o Kubernetes e boa parte da internet.

O Que É a Linguagem de Programação Ruby? Um Guia Simples da Linguagem Feita para a Felicidade
Um guia simples e sem jargões sobre o Ruby, a linguagem de programação feita para deixar os programadores felizes. Entenda por que o código Ruby parece inglês, como o Ruby on Rails move sites como GitHub e Shopify, e onde o Ruby brilha.
Comentários
Seja gentil e específico. Comentários com links de contas novas aparecem depois da análise de um moderador.