Apollo Server 4 em produção
Apollo Server 4 é framework-agnostic: você pluga em Express, Fastify, Koa, ou roda standalone. Plugins cobrem landing page, usage reporting, response cache, APQ, complexity. Error formatting é explícito: classifique erros (AuthenticationError, ValidationError, InternalError) e nunca vaze stack trace para o cliente.
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginCacheControl } from '@apollo/server/plugin/cacheControl';
import responseCachePlugin from '@apollo/server-plugin-response-cache';
const server = new ApolloServer({
schema,
plugins: [
ApolloServerPluginCacheControl({ defaultMaxAge: 60 }),
responseCachePlugin(),
],
formatError: (formatted, err) => {
if (formatted.extensions?.code === 'INTERNAL_SERVER_ERROR') {
logger.error(err);
return { message: 'Internal error', extensions: { code: 'INTERNAL' } };
}
return formatted;
},
});
await server.start();
app.use('/graphql', expressMiddleware(server, { context }));Caching: APQ + response cache
APQ tira o texto da query da URL/body e deixa apenas o hash — CDN cacheia por hash. Response cache guarda a resposta inteira por chave (hash + variáveis + hints de cacheControl do schema). Combine: campos marcados com @cacheControl(maxAge: 300, scope: PUBLIC) viram cacheáveis em CDN.
Regra: campos com scope PUBLIC são cacheáveis globalmente; PRIVATE apenas por-usuário. Nunca marque dados sensíveis como PUBLIC. A política mais restritiva da query vence.
Apollo Client normalized cache
import { ApolloClient, InMemoryCache, HttpLink, from } from '@apollo/client';
import { createPersistedQueryLink } from '@apollo/client/link/persisted-queries';
import { sha256 } from 'crypto-hash';
const client = new ApolloClient({
link: from([
createPersistedQueryLink({ sha256, useGETForHashedQueries: true }),
new HttpLink({ uri: '/graphql' }),
]),
cache: new InMemoryCache({
typePolicies: {
Post: {
fields: {
comments: { keyArgs: ['orderBy'], merge: mergeConnection },
},
},
},
}),
});typePolicies customizam merge de paginação e campos computados. Sem keyArgs correto, cache confunde listas paginadas. merge function concatena edges e preserva pageInfo.
Optimistic UI e fragment matching
Mutation com optimisticResponse pinta a UI antes da resposta chegar. Se o servidor diverge, Apollo reconcilia. Para unions/interfaces, configure possibleTypes (gerado via Apollo CLI a partir do schema) — caso contrário fragments em abstract types falham silenciosamente.