Executando verificação de segurança...
5

Breaking Change na API: remoção da estratégia "best" e informações adicionais de "parent" no objeto "content"

Turma, aviso importante 🤝

Para quem está se integrando na API do TabNews, nos próximos dias teremos 2 Breaking Changes na sua interface pública e são mudanças simples, mas importantes para continuarmos o processo de lapidar os dados que são devolvidos de forma programática até chegar ao ponto de concluirmos a versão beta dela.

Importante destacar que não temos urgência em fazer estas breaking changes, mas ao mesmo tempo não há porque esperar caso ninguém esteja diretamente usando esses parâmetros. Então caso ninguém esteja usando, iremos fazer o deploy das breaking changes nesta quinta-feira dia 25 de Agosto, mas caso você esteja usando e precise de mais tempo, sem problema algum e não hesite em deixar um comentário nessa publicação informando quanto tempo você precisa, combinado? 🤝

1) Remoção da strategy best no endpoint /api/v1/contents

Isto foi especificado nesta publicação no item 6) que anunciava que a estratégia best seria movida para relevant, onde por enquanto as duas estão sendo disponibilizadas pela API, porém nesta quinta-feira iremos remover o acesso a best.

Caso você possua algum client que implementou a paginação dos conteúdos do TabNews, fortemente sugerimos você utilizar o cabeçalho Link para que sua aplicação automaticamente utilize os links corretos (com a estratégia correta) daqui para frente. Isto significa que, se você utilizar este cabeçalho, você não precisará alterar sua aplicação para se adaptar a essa mudança. Caso queira mais informações sobre como isso funciona, sugiro ler essa publicação, é realmente muito massa aprender sobre isso.

2) Remoção das propriedades sobre parent no objeto content

Hoje o objeto content possui 4 propriedades relacionadas à publicação que está logo acima na árvore de conteúdos, que são:

  1. parent_id
  2. parent_title
  3. parent_slug
  4. parent_username

Exemplo: https://www.tabnews.com.br/api/v1/contents/gugadeschamps/f2385fcf-1385-4f70-ad54-6f842469a001

{
  "id": "eabc571e-222c-4d1e-aae5-580469a9f54d",
  "owner_id": "110cc974-4c56-4074-afbc-81ce22aa6013",
  "parent_id": "121c55a2-1ab4-48f3-9192-f0dece2a6877",
  "slug": "f2385fcf-1385-4f70-ad54-6f842469a001",
  "title": null,
  "body": "A cada atualização, eu fico impressionado com a quantidade de melhorias. \n\nFico muito contente com o carinho que todo mundo tem colocado nesse “pedaço especial de internet“!",
  "status": "published",
  "source_url": null,
  "created_at": "2022-08-23T10:13:10.804Z",
  "updated_at": "2022-08-23T10:13:10.804Z",
  "published_at": "2022-08-23T10:13:10.876Z",
  "deleted_at": null,
  "owner_username": "gugadeschamps",
  "parent_title": "Novas melhorias: Mais Performance e outras 6 melhorias 🎉",
  "parent_slug": "novas-melhorias-mais-performance-e-outras-6-melhorias",
  "parent_username": "filipedeschamps",
  "tabcoins": 5,
  "children_deep_count": 2
}

A proposta desta breaking change é manter apenas a propriedade parent_id (que é uma propriedade que existe de fato dentro do objeto content) e remover as 3 outras que são computadas para que elas possam ser acessadas por um novo endpoint /parent, seguindo exatamente o mesmo princípio do novo endpoint /root.

Então usando a mesma publicação acima, hoje você já consegue acessar o conteúdo raiz a partir de um outro conteúdo filho, independente da profundidade:

https://www.tabnews.com.br/api/v1/contents/gugadeschamps/f2385fcf-1385-4f70-ad54-6f842469a001/root

O mesmo princípio será utilizado para conseguir acessar o conteúdo que está 1 nível acima:

https://www.tabnews.com.br/api/v1/contents/gugadeschamps/f2385fcf-1385-4f70-ad54-6f842469a001/parent (ainda não disponível)

Os motivos desta alteração são três:

  1. Simplificar e otimizar o código, pois são feitos dois JOINs para construir esta informação tanto na consulta, criação quanto na atualização dos conteúdos.
  2. Parar de devolver esta informação que na maioria dos casos não é utilizada, como por exemplo na lista de conteúdos. Hoje os dados computados são utilizados apenas em situações onde você quer linkar uma coisa na outra, como por exemplo na página exclusiva de uma resposta, que na verdade é a única utilização hoje no client web do TabNews, pois até o sistema de notificações já está usando a estratégia nova do root.
  3. Ter melhor controle quando um conteúdo parent está com o status em deleted, pois hoje estamos mostrando as informações de um conteúdo deletado por estas propriedades. Então a ideia é centralizar o acesso a estas informações em um único lugar e controlar o comportamento por lá.

Então seguindo o exemplo do /root, quando o conteúdo raiz está com status deleted e você tenta acessar ele, é retornado um 404. Pensando aqui, não sei se esse é o melhor comportamento, pois talvez seja melhor retornar o objeto inteiro (incluindo a data em deleted_at) mas as informações como title e body retornarem um valor fixo [Removido] ou algo assim.

Acredito que será mais proveitoso e fácil para as interfaces se adaptarem a um status deleted com informações úteis (e não sensíveis) da publicação original do que retornar um 404.

Em resumo: simplificar a interface pública do objeto, estancar complexidade e centralizar comportamento.

Conclusão

Qualquer comentário é bem vindo e vamos lapidando a API para que seja a melhor do Brasil no consumo de conteúdos sobre Programação e Tecnologia 🤝

Carregando publicação patrocinada...
3

Gosto bastante da ideia de retornar algum dado que sirva para informar que um dia aquele conteúdo existiu. Bem melhor do que o 404, mas talvez só devolveria o status deletado e nada mais.

Sobre os endpoints, chegou a pensar em devolver tudo no mesmo endpoint /api/v1/contents/[username]/[slug]? Mas somente se esses dados forem solicitados via parâmetros.

Poderia ter o parâmetro root e o parent. Abriria alternativa até para o branch que para o banco de dados tem o mesmo peso que buscar o root.

A vantagem seria buscar todos os dados necessários com somente uma consulta tanto para a API como para o BD.

[Edit]
Para facilitar o cache do retorno, pode ter só um parâmetro tree, em que o padrão seja none, mas que aceite também root ou parent. Isso facilita no futuro existir o branch e o all. Sendo que o útltimo retornaria a árvore inteira a partir do root.

1

Gosto bastante da ideia de retornar algum dado que sirva para informar que um dia aquele conteúdo existiu. Bem melhor do que o 404, mas talvez só devolveria o status deletado e nada mais.

Gosto da ideia de retornar a estrutura inteira para que a interface precise se preocupar menos em como reagir a um caso desses. Inclusive, gosto da ideia de continuar retornando o owner_username para identificar de quem era a publicação e o deleted_at para saber quando ela foi removida. Mais para frente isso deveria ser retornado também na árvore de respostas para continar mostrando a árvore inteira. Essa ideia foi dada no passado por outra pessoa em outro momento, não lembro mais exatamente quando foi.

Sobre os endpoints, chegou a pensar em devolver tudo no mesmo endpoint /api/v1/contents/[username]/[slug]? Mas somente se esses dados forem solicitados via parâmetros.

Interessantíssimo e eu bolei 3 respostas de tanto que isso me deixou pensando 😂

Resposta 1

Se eu não me engano, sugeriram isso também no passado de incluir uma chave parent com todo o objeto ali dentro e juntanto com sua ideia ficaria show escolher quando receber o objeto parent, root (e até o children?) que pelo que entendi ali no [Edit] você sugeriu que daria para retornar pela chave tree, correto?.

Bom, com isso podemos tombar o /root, /children mas meu medo é começar a colocar muita complexidade dentro da mesma coisa, porque o jeito que está o model content hoje, principalmente o método findAll(), me dá medo. É muita complexidade que vai criando densidade num só lugar.

Resposta 2

Talvez possa ser interessante ter endpoints distintos, para justamente não precisar pagar o custo inteiro de demora quando você quer abrir o conteúdo principal para em seguida deixar as outras informações chegando e sendo exibidas de forma assíncrona. No caso do client web do TabNews isso não vai fazer diferença, pois acabamos pagando esse custo inteiramente na geração do estático.

Resposta 3

Meio que a continuação da Resposta 1 sobre o meu medo de complexidade estar em um único local e será que nessas horas a gente não deveria já estar usando um ORM para montar essas relações ou talvez usar GraphQL? No caso do ORM é sobre a facilidade de relacionar e buscar os conteúdos com uma interface mais limpa e mais segura do que temos hoje, e no caso do GraphQL de ter flexibilidade total em que dado buscar e da onde.

Não recomendo nenhuma dessas duas opções para agora, só queria deixar registrado para food for thought.

Sugestão de como avançar

  1. Pelo fato de já termos o /children e agora o /root, sugiro implementar o /parent.
  2. É uma movimentação muito fácil e isto vai trazer benefícios imediatamente, como isolar complexidade e normalizar a interface (de dados adicionais estarem disponíveis em sub-rotas). Gostaria de saber analisar qual o impacto de remover os dois JOINs das queries, mas não sei analisar isso hoje, então não sei se terá algum ganho de performance parar de fazer eles, tomara que tenha.
  3. Com isso feito, sugiro mais para frente parar para pensar o que fazer com o model content e também se faz sentido manter a API em beta para propor novos breaking changes conforme o uso real dos clients.