From 3435ec944def7dcd65089e70ac091f46e8571699 Mon Sep 17 00:00:00 2001 From: Arthur Fiorette Date: Thu, 25 Apr 2024 00:31:54 -0300 Subject: [PATCH] feat: initial kita post --- src/content/blog/the-cost-of-return-await.md | 2 +- .../type-safe-meta-router-typescript-diy.md | 155 ++++++++++++++++++ ...st-abstractions-typescript-compiler-api.md | 40 ----- src/content/config.ts | 2 +- src/pages/[slug].astro | 30 ++++ src/pages/index.astro | 2 +- src/styles/colors.scss | 2 + 7 files changed, 190 insertions(+), 43 deletions(-) create mode 100644 src/content/blog/type-safe-meta-router-typescript-diy.md delete mode 100644 src/content/blog/zero-cost-abstractions-typescript-compiler-api.md diff --git a/src/content/blog/the-cost-of-return-await.md b/src/content/blog/the-cost-of-return-await.md index cb82a6f..81f6d35 100644 --- a/src/content/blog/the-cost-of-return-await.md +++ b/src/content/blog/the-cost-of-return-await.md @@ -3,7 +3,7 @@ title: 'How Return Await can slow down your code' date: 2022/03/26 08:17:00 keywords: [performance, javascript] description: Awaiting a promise before returning it slows down your code. -published: true +# published: true ---
+ Fastify + +```ts +// You can also use github.com/fastify/fastify-type-provider-typebox but +// that's not out of the box +app.post( + '/user/:id', + { + schema: { + params: { + type: 'object', + properties: { + id: { type: 'string' } + } + }, + body: { + type: 'object', + properties: { + name: { type: 'string' } + } + }, + response: { + 200: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' } + } + } + } + } + }, + async (req, res) => { + return myService.editUser(req.params.id, req.body); + } +); +``` + + + +
+ Elysia + +```ts +elysia.get( + '/user/:id', + async () => { + return myService.editUser(req.params.id, req.body); + }, + { + params: t.Object({ + id: t.Numeric() + }), + body: t.Object({ + name: t.String() + }), + response: t.Object({ + id: t.String(), + name: t.String() + }) + } +); +``` + +
+ +E por aí vai... + +A repetição piora mil vezes mais quando você tem que definir os mesmos modelos no SQL do Banco de Dados, na tipagem da sua ORM, na Documentação da sua API e em vários outros lugares, todos ao mesmo tempo. + +Definir o mesmo modelo umas 5 vezes não costuma ser um grande problema em grandes projetos, afinal projetos grandes/empresariais são os que realmente pagam as contas no final do mês. + +Apenas usando Ctrl+C/Ctrl+V e algumas mudanças que podem ser facilitadas com regexes dentre as _N_ cópias de schema que precisam ser feitas já podem ser o suficiente. + +O grande problema disso tudo mora em manter a consistência entre essas cópias durante os longos anos de vida de um projeto e todas as suas mudanças que o tempo trará consigo. + +## Esboçando ideias + +Antes de decidir o que precisamos e podemos reduzir, vamos tentar esboçar um exemplo mínimo de uma rota sem perder nenhuma informação: + +```ts +export function createUser(id: string, name: string) { + return myService.editUser(id, name); +} +``` + +Tecnicamente, o código acima nos diz tudo que é necessário, porém **ainda** está faltando algumas informações específicas que são necessárias para um web service. + +Se você se acha o rei da arquitetura de software, você provavelmente deve estar pensando: + +> _"Whoa! That's what a Controller should do!"_ + +Sim, de certa forma você não está errado, mas lembre-se que estamos programando em JavaScript e com isso podemos burlar algumas coisas em favor da tão sonhada **Developer Experience**. + +Informações como: + +- O método HTTP que a rota deve responder +- O caminho da rota +- De onde o ID do usuário vem +- De onde o nome do usuário vem +- O que será retornado +- _(E muitas outras informações que não convém ao nosso exemplo)_ + +Ainda precisam ser definidas de alguma forma. Poderiamos melhorar um pouco mais o nosso exemplo para conter essas informações: + +```ts +// routes/user.ts + +type Body = T; +type Path = T; +type User = { id: string; name: string }; + +/** + * @operationId createUser + */ +export function post(id: Path, name: Body): User { + return myService.editUser(id, name); +} +``` + +E ao colocar o código acima dentro de um arquivo localizado em `/routes/user.ts` e seguir a metodologia de filesystem routing, tecnicamente já temos toda a informação necessária definida de forma explícita e sem repetição. + +Mesmo que aparenta perfeito, o exemplo acima não consegue ser executado sem etapas de compilação adicionais, uma vez que ao transpilar o código typescript para javascript antes de executá-lo, todas essas informações serão perdidas e não conseguiremos mais acessá-las: + +```js +// routes/user.js + +// We lost all the information we had in the typescript file +export function post(id, name) { + return myService.editUser(id, name); +} +``` + +## Typescript, but not the one you know + +Se você se considera um pouco mais curioso, já deve ter se perguntado como que ao rodar `tsc` e a tipagem ser removida mas o código não. + +Como que `export function post(id` continuou no `.js` mas o `: Path` foi removido? diff --git a/src/content/blog/zero-cost-abstractions-typescript-compiler-api.md b/src/content/blog/zero-cost-abstractions-typescript-compiler-api.md deleted file mode 100644 index 6525aaf..0000000 --- a/src/content/blog/zero-cost-abstractions-typescript-compiler-api.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: 'Write abstractions without runtime cost using the Typescript Compiler API' -date: 2023/11/13 02:20:00 -keywords: [typescript, meta programming] -description: - Read your code and generate more code. Embrace meta programming and write type safe code - at compile time. ---- - -I'm not going to showcase this project for you because this is the engine that powers this -website by itself. You can check the source code, the only JS that will ever run in your -browser is my analytics script to see how famous I'm currently. - -This entire website is built from ground up using two technologies: JSX to generate Html -and Parcel to bundle the assets. - -Every page is a default function that returns a html string built using `Kita`'s JSX to -Html runtime. - -```tsx -export default function Index(): string { - return ( - - - My website - - -

Hello World!

- - - ); -} - - === '...'; -``` - -If the above felt super weird to you, then you're probably used to `React`. I have another -blog post that explains when you are looking to JSX and when you're actually interacting -with `React`-like libraries/frameworks: -[Detaching JSX from React](/detaching-jsx-from-react). diff --git a/src/content/config.ts b/src/content/config.ts index e7ccffb..62c5f79 100644 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -8,7 +8,7 @@ const blog = defineCollection({ description: z.string(), date: z.coerce.date(), keywords: z.array(z.string()), - published: z.boolean().optional(), + published: z.union([z.boolean(), z.literal('preview')]).default(false), }) }); diff --git a/src/pages/[slug].astro b/src/pages/[slug].astro index 288de3d..1e0d297 100644 --- a/src/pages/[slug].astro +++ b/src/pages/[slug].astro @@ -50,6 +50,12 @@ const { Content } = await post.render();

{post.data.title}

{post.data.description} + + { + post.data.published === 'preview' && ( +
This post is a preview and may not be final.
+ ) + }
@@ -147,6 +153,17 @@ const { Content } = await post.render(); } } } + + .preview { + margin-top: 5rem; + margin-bottom: 5rem; + padding: 2rem; + text-align: center; + font-size: 2rem; + background-color: #f5a623; + border: 1px solid var(--shade-outline); + border-radius: 0.5rem; + }