[{"data":1,"prerenderedAt":941},["ShallowReactive",2],{"tag-openapi":3},[4,551],{"id":5,"title":6,"body":7,"categories":530,"coverImage":532,"date":533,"description":534,"extension":535,"meta":536,"navigation":164,"path":537,"seo":538,"stem":539,"sticky":164,"tags":540,"__hash__":550},"articles/crudio-da-una-spec-openapi-a-un-backend-mock-stateful.md","Crudio: da una spec OpenAPI a un backend mock stateful con un comando",{"type":8,"value":9,"toc":523},"minimark",[10,22,27,30,37,42,45,69,72,85,89,92,95,123,126,221,225,236,386,393,435,438,442,445,455,461,464,468,483,486,512,519],[11,12,13],"p",{},[14,15,16,17,21],"em",{},"In questo post voglio raccontarti perché ho costruito ",[18,19,20],"strong",{},"Crudio"," e il problema preciso che risolve: avere un backend finto che però si comporta come un backend vero, derivandolo interamente dalla tua spec OpenAPI.",[11,23,24],{},[14,25,26],{},"Non è l'ennesimo mock server che restituisce risposte preconfezionate. È un backend che ricorda cosa ci hai scritto dentro.",[11,28,29],{},"Chiunque sviluppi frontend conosce la stessa frustrazione: ti serve un backend per lavorare, ma quello vero non è pronto, è instabile, o semplicemente non vuoi dipenderci durante i test. Così ripieghi su un mock server.",[11,31,32,33,36],{},"E qui scatta il problema. ",[18,34,35],{},"I mock server ti costringono a una scelta che non dovresti dover fare",": o sono guidati dalla spec, oppure sono stateful. Mai entrambe le cose.",[38,39,41],"h2",{"id":40},"il-buco-che-nessuno-riempie","Il buco che nessuno riempie",[11,43,44],{},"Mettiamola così, con gli strumenti che probabilmente già usi:",[46,47,48,59],"ul",{},[49,50,51,54,55,58],"li",{},[18,52,53],{},"Prism"," legge la tua spec OpenAPI ed è fedele al contratto, ma è ",[14,56,57],{},"stateless",". Fai una POST e il dato sparisce alla GET successiva. Ottimo per uno smoke test, inutile quando devi verificare un flusso reale.",[49,60,61,64,65,68],{},[18,62,63],{},"json-server"," è stateful e ti dà CRUD persistente, ma ",[18,66,67],{},"ignora completamente la tua spec"," e non valida nulla. Accetta felicemente payload che il tuo backend vero rifiuterebbe a priori.",[11,70,71],{},"Il risultato è che, quando devo testare sul serio come il frontend gestisce paginazione, errori di validazione, 404 e update parziali, nessuno dei due basta.",[11,73,74,84],{},[18,75,76,77,80,81,83],{},"Crudio nasce esattamente per riempire quella casella vuota: spec-driven ",[14,78,79],{},"e"," stateful ",[14,82,79],{}," con validazione."," Tutto derivato dal tuo contratto OpenAPI, niente scritto a mano.",[38,86,88],{"id":87},"cosa-fa-in-pratica","Cosa fa, in pratica",[11,90,91],{},"Crudio legge una spec OpenAPI 3.x e tira su un'API mock funzionante con persistenza. Gli endpoint CRUD si comportano come un piccolo backend reale; gli endpoint non-CRUD mantengono uno stato per-operazione, così l'intera spec è servibile da un unico runtime.",[11,93,94],{},"Nel concreto:",[46,96,97,103,110,117,120],{},[49,98,99,100],{},"i request body CRUD sono ",[18,101,102],{},"validati contro il tuo schema",[49,104,105,106,109],{},"i dati ",[18,107,108],{},"persistono tra una chiamata e l'altra"," (file JSON, nessun database da configurare)",[49,111,112,113,116],{},"gli ",[18,114,115],{},"ID sono generati in base alla spec"," (interi, UUID, ecc.)",[49,118,119],{},"le route CRUD condividono lo stato della risorsa",[49,121,122],{},"le route non-CRUD usano uno stato di operazione persistito",[11,124,125],{},"E si avvia con un solo comando:",[127,128,133],"pre",{"className":129,"code":130,"language":131,"meta":132,"style":132},"language-bash shiki shiki-themes github-light github-dark","# Contro qualsiasi spec OpenAPI 3.x\nnpx @enricodeleo/crudio ./openapi.yaml\n\n# Con dati fake\nnpx @enricodeleo/crudio ./openapi.yaml --seed 10\n\n# Porta e storage personalizzati\nnpx @enricodeleo/crudio ./openapi.yaml --port 8080 --data-dir /tmp/data\n","bash","",[134,135,136,145,159,166,172,189,194,200],"code",{"__ignoreMap":132},[137,138,141],"span",{"class":139,"line":140},"line",1,[137,142,144],{"class":143},"sJ8bj","# Contro qualsiasi spec OpenAPI 3.x\n",[137,146,148,152,156],{"class":139,"line":147},2,[137,149,151],{"class":150},"sScJk","npx",[137,153,155],{"class":154},"sZZnC"," @enricodeleo/crudio",[137,157,158],{"class":154}," ./openapi.yaml\n",[137,160,162],{"class":139,"line":161},3,[137,163,165],{"emptyLinePlaceholder":164},true,"\n",[137,167,169],{"class":139,"line":168},4,[137,170,171],{"class":143},"# Con dati fake\n",[137,173,175,177,179,182,186],{"class":139,"line":174},5,[137,176,151],{"class":150},[137,178,155],{"class":154},[137,180,181],{"class":154}," ./openapi.yaml",[137,183,185],{"class":184},"sj4cs"," --seed",[137,187,188],{"class":184}," 10\n",[137,190,192],{"class":139,"line":191},6,[137,193,165],{"emptyLinePlaceholder":164},[137,195,197],{"class":139,"line":196},7,[137,198,199],{"class":143},"# Porta e storage personalizzati\n",[137,201,203,205,207,209,212,215,218],{"class":139,"line":202},8,[137,204,151],{"class":150},[137,206,155],{"class":154},[137,208,181],{"class":154},[137,210,211],{"class":184}," --port",[137,213,214],{"class":184}," 8080",[137,216,217],{"class":184}," --data-dir",[137,219,220],{"class":154}," /tmp/data\n",[38,222,224],{"id":223},"si-comporta-come-un-backend-vero","Si comporta come un backend vero",[11,226,227,228,231,232,235],{},"Data una spec CRUD standard con path tipo ",[134,229,230],{},"/pets"," e ",[134,233,234],{},"/pets/{petId}",", ottieni un backend che fa quello che ti aspetti:",[127,237,239],{"className":129,"code":238,"language":131,"meta":132,"style":132},"# Create\ncurl -X POST http://localhost:3000/pets \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\":\"Rex\",\"tag\":\"dog\"}'\n# → 201 {\"id\":1,\"name\":\"Rex\",\"tag\":\"dog\"}\n\n# Get by ID — il dato è ancora lì, persistito su disco\ncurl http://localhost:3000/pets/1\n# → 200 {\"id\":1,\"name\":\"Rex\",\"tag\":\"dog\"}\n\n# Partial update\ncurl -X PATCH http://localhost:3000/pets/1 \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"tag\":\"cat\"}'\n# → 200 {\"id\":1,\"name\":\"Rex\",\"tag\":\"cat\"}\n\n# Delete\ncurl -X DELETE http://localhost:3000/pets/1\n# → 204\n",[134,240,241,246,263,273,281,286,290,295,302,308,313,319,334,343,351,357,362,368,380],{"__ignoreMap":132},[137,242,243],{"class":139,"line":140},[137,244,245],{"class":143},"# Create\n",[137,247,248,251,254,257,260],{"class":139,"line":147},[137,249,250],{"class":150},"curl",[137,252,253],{"class":184}," -X",[137,255,256],{"class":154}," POST",[137,258,259],{"class":154}," http://localhost:3000/pets",[137,261,262],{"class":184}," \\\n",[137,264,265,268,271],{"class":139,"line":161},[137,266,267],{"class":184},"  -H",[137,269,270],{"class":154}," 'Content-Type: application/json'",[137,272,262],{"class":184},[137,274,275,278],{"class":139,"line":168},[137,276,277],{"class":184},"  -d",[137,279,280],{"class":154}," '{\"name\":\"Rex\",\"tag\":\"dog\"}'\n",[137,282,283],{"class":139,"line":174},[137,284,285],{"class":143},"# → 201 {\"id\":1,\"name\":\"Rex\",\"tag\":\"dog\"}\n",[137,287,288],{"class":139,"line":191},[137,289,165],{"emptyLinePlaceholder":164},[137,291,292],{"class":139,"line":196},[137,293,294],{"class":143},"# Get by ID — il dato è ancora lì, persistito su disco\n",[137,296,297,299],{"class":139,"line":202},[137,298,250],{"class":150},[137,300,301],{"class":154}," http://localhost:3000/pets/1\n",[137,303,305],{"class":139,"line":304},9,[137,306,307],{"class":143},"# → 200 {\"id\":1,\"name\":\"Rex\",\"tag\":\"dog\"}\n",[137,309,311],{"class":139,"line":310},10,[137,312,165],{"emptyLinePlaceholder":164},[137,314,316],{"class":139,"line":315},11,[137,317,318],{"class":143},"# Partial update\n",[137,320,322,324,326,329,332],{"class":139,"line":321},12,[137,323,250],{"class":150},[137,325,253],{"class":184},[137,327,328],{"class":154}," PATCH",[137,330,331],{"class":154}," http://localhost:3000/pets/1",[137,333,262],{"class":184},[137,335,337,339,341],{"class":139,"line":336},13,[137,338,267],{"class":184},[137,340,270],{"class":154},[137,342,262],{"class":184},[137,344,346,348],{"class":139,"line":345},14,[137,347,277],{"class":184},[137,349,350],{"class":154}," '{\"tag\":\"cat\"}'\n",[137,352,354],{"class":139,"line":353},15,[137,355,356],{"class":143},"# → 200 {\"id\":1,\"name\":\"Rex\",\"tag\":\"cat\"}\n",[137,358,360],{"class":139,"line":359},16,[137,361,165],{"emptyLinePlaceholder":164},[137,363,365],{"class":139,"line":364},17,[137,366,367],{"class":143},"# Delete\n",[137,369,371,373,375,378],{"class":139,"line":370},18,[137,372,250],{"class":150},[137,374,253],{"class":184},[137,376,377],{"class":154}," DELETE",[137,379,301],{"class":154},[137,381,383],{"class":139,"line":382},19,[137,384,385],{"class":143},"# → 204\n",[11,387,388,389,392],{},"E soprattutto ",[18,390,391],{},"rifiuta ciò che il tuo backend vero rifiuterebbe",", perché valida contro lo schema:",[127,394,396],{"className":129,"code":395,"language":131,"meta":132,"style":132},"curl -X POST http://localhost:3000/pets \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"tag\":\"dog\"}'\n# → 400 {\"error\":\"Validation failed\",\"details\":[...]}\n# rifiutato: `name` è obbligatorio nel tuo schema\n",[134,397,398,410,418,425,430],{"__ignoreMap":132},[137,399,400,402,404,406,408],{"class":139,"line":140},[137,401,250],{"class":150},[137,403,253],{"class":184},[137,405,256],{"class":154},[137,407,259],{"class":154},[137,409,262],{"class":184},[137,411,412,414,416],{"class":139,"line":147},[137,413,267],{"class":184},[137,415,270],{"class":154},[137,417,262],{"class":184},[137,419,420,422],{"class":139,"line":161},[137,421,277],{"class":184},[137,423,424],{"class":154}," '{\"tag\":\"dog\"}'\n",[137,426,427],{"class":139,"line":168},[137,428,429],{"class":143},"# → 400 {\"error\":\"Validation failed\",\"details\":[...]}\n",[137,431,432],{"class":139,"line":174},[137,433,434],{"class":143},"# rifiutato: `name` è obbligatorio nel tuo schema\n",[11,436,437],{},"Questa è la differenza che conta: non stai testando contro risposte finte, stai testando contro il tuo contratto.",[38,439,441],{"id":440},"per-cosa-usarlo-e-per-cosa-no","Per cosa usarlo (e per cosa no)",[11,443,444],{},"Voglio essere onesto sui confini, perché è la parte che di solito viene nascosta.",[11,446,447,450,451,454],{},[18,448,449],{},"Usalo per:"," test di integrazione, sviluppo frontend, prototipazione di API, verifica del contratto. È costruito su ",[18,452,453],{},"Express 5 + ajv",", persiste su file JSON, ed è pensato per girare ovunque senza dipendenze pesanti.",[11,456,457,460],{},[18,458,459],{},"Non usarlo per:"," backend di produzione, load testing, o qualunque cosa richieda business logic specifica di dominio senza handler custom. Crudio non inventa logica che non sia nel contratto.",[11,462,463],{},"Allo stato attuale lo stato è per-risorsa: relazioni, foreign key e autenticazione sono le domande ovvie successive, ed è esattamente lì che mi piacerebbe capire dove andare a tracciare la linea del \"comportarsi come un backend vero\".",[38,465,467],{"id":466},"provalo","Provalo",[11,469,470,471,474,475,482],{},"Crudio è ",[18,472,473],{},"open source, licenza MIT",", e lo trovi su GitHub: ",[476,477,481],"a",{"href":478,"rel":479},"https://github.com/enricodeleo/crudio",[480],"nofollow","github.com/enricodeleo/crudio",".",[11,484,485],{},"Per installarlo una volta sola e accorciare il comando:",[127,487,489],{"className":129,"code":488,"language":131,"meta":132,"style":132},"npm i -g @enricodeleo/crudio\ncrudio ./openapi.yaml\n",[134,490,491,505],{"__ignoreMap":132},[137,492,493,496,499,502],{"class":139,"line":140},[137,494,495],{"class":150},"npm",[137,497,498],{"class":154}," i",[137,500,501],{"class":184}," -g",[137,503,504],{"class":154}," @enricodeleo/crudio\n",[137,506,507,510],{"class":139,"line":147},[137,508,509],{"class":150},"crudio",[137,511,158],{"class":154},[11,513,514,515,482],{},"Se lo provi e ti torna utile — o se hai un'idea su dove dovrebbe fermarsi il confine tra \"mock\" e \"backend vero\" — scrivimene: ne parliamo nei commenti oppure ",[476,516,518],{"href":517},"mailto:hello@enricodeleo.com","contattami",[520,521,522],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":132,"searchDepth":147,"depth":147,"links":524},[525,526,527,528,529],{"id":40,"depth":147,"text":41},{"id":87,"depth":147,"text":88},{"id":223,"depth":147,"text":224},{"id":440,"depth":147,"text":441},{"id":466,"depth":147,"text":467},[531],"dev",null,"2026-06-30T09:00:00.000Z","Ho costruito Crudio, uno strumento open source che trasforma una spec OpenAPI 3.x in un backend mock vero: stateful, con validazione sullo schema e persistenza su disco. Tutto derivato dal tuo contratto.","md",{},"/crudio-da-una-spec-openapi-a-un-backend-mock-stateful",{"title":6,"description":534},"crudio-da-una-spec-openapi-a-un-backend-mock-stateful",[541,542,543,544,545,546,547,548,549],"openapi","api","mock","javascript","nodejs","express","testing","frontend","opensource","41PVj89zXppGTYqqZy-gKG579Ew_d6Q7vo873Z0xwrw",{"id":552,"title":553,"body":554,"categories":927,"coverImage":929,"date":930,"description":931,"extension":535,"meta":932,"navigation":164,"path":933,"seo":934,"stem":935,"sticky":164,"tags":936,"__hash__":940},"articles/generare-sdk-javascript-waterline-con-aquasdk.md","AquaSDK: Genera SDK JavaScript in stile Waterline da specifiche OpenAPI",{"type":8,"value":555,"toc":917},[556,567,571,597,601,606,662,709,713,750,754,837,841,848,859,863,882,885,890,908,914],[11,557,558,559,562,563,566],{},"Nel mondo dello sviluppo moderno, la capacità di ",[18,560,561],{},"integrare rapidamente API"," è tanto cruciale quanto frustrante. Quante ore abbiamo perso a scrivere manualmente client SDK pieni di boilerplate? È per risolvere questo problema che ho creato ",[18,564,565],{},"AquaSDK",", uno strumento open-source che genera automaticamente SDK JavaScript con sintassi fluida e intuitiva partendo da qualsiasi specifica OpenAPI.",[38,568,570],{"id":569},"perché-automatizzare-la-generazione-di-sdk","Perché automatizzare la generazione di SDK?",[46,572,573,579,585,591],{},[49,574,575,578],{},[18,576,577],{},"⏱️ Riduzione del 70% del tempo di sviluppo"," per integrazioni API",[49,580,581,584],{},[18,582,583],{},"🔒 Consistenza automatica"," tra documentazione OpenAPI e implementazione",[49,586,587,590],{},[18,588,589],{},"🚀 Esperienza developer-friendly"," con sintassi simile a Waterline ORM",[49,592,593,596],{},[18,594,595],{},"💡 Supporto nativo a Promise/async"," per codice asincrono pulito",[38,598,600],{"id":599},"funzionalità-avanzate-per-sviluppatori","Funzionalità avanzate per sviluppatori",[602,603,605],"h3",{"id":604},"per-gli-integratori-api","Per gli Integratori API",[46,607,608,648,656],{},[49,609,610,613,616,617],{},[18,611,612],{},"Sintassi a catena fluida",[614,615],"br",{},"\nInteragisci con le API come se utilizzassi un ORM:",[127,618,621],{"className":619,"code":620,"language":544,"meta":132,"style":132},"language-javascript shiki shiki-themes github-light github-dark","await api.utenti\n  .find({ ruolo: 'admin', iscrizione: { '>': '2024-01-01' } })\n  .limit(10)\n  .populate('ordini')\n  .execute();\n",[134,622,623,628,633,638,643],{"__ignoreMap":132},[137,624,625],{"class":139,"line":140},[137,626,627],{},"await api.utenti\n",[137,629,630],{"class":139,"line":147},[137,631,632],{},"  .find({ ruolo: 'admin', iscrizione: { '>': '2024-01-01' } })\n",[137,634,635],{"class":139,"line":161},[137,636,637],{},"  .limit(10)\n",[137,639,640],{"class":139,"line":168},[137,641,642],{},"  .populate('ordini')\n",[137,644,645],{"class":139,"line":174},[137,646,647],{},"  .execute();\n",[49,649,650,653,655],{},[18,651,652],{},"Validazione automatica",[614,654],{},"\nControllo degli input basato sugli schemi OpenAPI prima delle chiamate API",[49,657,658,661],{},[18,659,660],{},"Generazione completa dell'SDK","*\nAquaSDK non si limita a produrre semplici wrapper API. Ogni SDK generato include:",[127,663,665],{"className":129,"code":664,"language":131,"meta":132,"style":132},"├── README.md # Documentazione automatica con esempi d'uso\n├── models/   # Modelli dati validati basati sugli schemi OpenAPI\n├── resources/ # Controller pronti per ogni endpoint API\n└── utils/     # Helper per query complesse\n",[134,666,667,678,688,698],{"__ignoreMap":132},[137,668,669,672,675],{"class":139,"line":140},[137,670,671],{"class":150},"├──",[137,673,674],{"class":154}," README.md",[137,676,677],{"class":143}," # Documentazione automatica con esempi d'uso\n",[137,679,680,682,685],{"class":139,"line":147},[137,681,671],{"class":150},[137,683,684],{"class":154}," models/",[137,686,687],{"class":143},"   # Modelli dati validati basati sugli schemi OpenAPI\n",[137,689,690,692,695],{"class":139,"line":161},[137,691,671],{"class":150},[137,693,694],{"class":154}," resources/",[137,696,697],{"class":143}," # Controller pronti per ogni endpoint API\n",[137,699,700,703,706],{"class":139,"line":168},[137,701,702],{"class":150},"└──",[137,704,705],{"class":154}," utils/",[137,707,708],{"class":143},"     # Helper per query complesse\n",[602,710,712],{"id":711},"per-i-maintainer","Per i Maintainer",[46,714,715,742],{},[49,716,717,720],{},[18,718,719],{},"Configurazione plug-and-play",[127,721,723],{"className":129,"code":722,"language":131,"meta":132,"style":132},"generate-sdk ./swagger.json ./sdk 1.0.0 --verbose\n",[134,724,725],{"__ignoreMap":132},[137,726,727,730,733,736,739],{"class":139,"line":140},[137,728,729],{"class":150},"generate-sdk",[137,731,732],{"class":154}," ./swagger.json",[137,734,735],{"class":154}," ./sdk",[137,737,738],{"class":184}," 1.0.0",[137,740,741],{"class":184}," --verbose\n",[49,743,744,747,749],{},[18,745,746],{},"Integrazione CI/CD",[614,748],{},"\nRigenera automaticamente l'SDK ad ogni aggiornamento dell'API",[38,751,753],{"id":752},"come-iniziare-in-3-passi","Come iniziare in 3 passi",[755,756,757,777,800],"ol",{},[49,758,759,760],{},"Installa il pacchetto globale:",[127,761,763],{"className":129,"code":762,"language":131,"meta":132,"style":132},"npm install -g aquasdk\n",[134,764,765],{"__ignoreMap":132},[137,766,767,769,772,774],{"class":139,"line":140},[137,768,495],{"class":150},[137,770,771],{"class":154}," install",[137,773,501],{"class":184},[137,775,776],{"class":154}," aquasdk\n",[49,778,779,780],{},"Genera il tuo SDK:",[127,781,783],{"className":129,"code":782,"language":131,"meta":132,"style":132},"generate-sdk ./api-spec.yaml ./sdk --version 1.0.0\n",[134,784,785],{"__ignoreMap":132},[137,786,787,789,792,794,797],{"class":139,"line":140},[137,788,729],{"class":150},[137,790,791],{"class":154}," ./api-spec.yaml",[137,793,735],{"class":154},[137,795,796],{"class":184}," --version",[137,798,799],{"class":184}," 1.0.0\n",[49,801,802,803],{},"Integra nel tuo progetto:",[127,804,806],{"className":619,"code":805,"language":544,"meta":132,"style":132},"import API from './sdk';\n\nconst api = new API({\n  baseUrl: 'https://api.azienda.com',\n  auth: { token: process.env.API_KEY }\n});\n",[134,807,808,813,817,822,827,832],{"__ignoreMap":132},[137,809,810],{"class":139,"line":140},[137,811,812],{},"import API from './sdk';\n",[137,814,815],{"class":139,"line":147},[137,816,165],{"emptyLinePlaceholder":164},[137,818,819],{"class":139,"line":161},[137,820,821],{},"const api = new API({\n",[137,823,824],{"class":139,"line":168},[137,825,826],{},"  baseUrl: 'https://api.azienda.com',\n",[137,828,829],{"class":139,"line":174},[137,830,831],{},"  auth: { token: process.env.API_KEY }\n",[137,833,834],{"class":139,"line":191},[137,835,836],{},"});\n",[38,838,840],{"id":839},"perché-open-source","Perché open-source?",[11,842,843,844,847],{},"AquaSDK è rilasciato sotto licenza ",[18,845,846],{},"GPL-3.0"," perché credo che:",[46,849,850,853,856],{},[49,851,852],{},"Gli strumenti fondamentali per lo sviluppo debbano essere accessibili a tutti",[49,854,855],{},"La collaborazione comunitaria produce soluzioni migliori",[49,857,858],{},"La trasparenza genera fiducia",[38,860,862],{"id":861},"prossimi-sviluppi","Prossimi sviluppi",[46,864,867,876],{"className":865},[866],"contains-task-list",[49,868,871,875],{"className":869},[870],"task-list-item",[872,873],"input",{"disabled":164,"type":874},"checkbox"," Generazione automatica di documentazione SDK",[49,877,879,881],{"className":878},[870],[872,880],{"disabled":164,"type":874}," Supporto Typescript",[883,884],"hr",{},[11,886,887],{},[18,888,889],{},"Vuoi provare AquaSDK o contribuire al progetto?",[46,891,892,900],{},[49,893,894,895],{},"🐙 GitHub: ",[476,896,899],{"href":897,"rel":898},"https://github.com/enricodeleo/aquasdk",[480],"github.com/enricodeleo/aquasdk",[49,901,902,903],{},"📦 npm: ",[476,904,907],{"href":905,"rel":906},"https://www.npmjs.com/package/aquasdk",[480],"npmjs.com/package/aquasdk",[11,909,910,911,482],{},"Per integrazioni enterprise o supporto personalizzato, ",[476,912,913],{"href":517},"contattami direttamente",[520,915,916],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":132,"searchDepth":147,"depth":147,"links":918},[919,920,924,925,926],{"id":569,"depth":147,"text":570},{"id":599,"depth":147,"text":600,"children":921},[922,923],{"id":604,"depth":161,"text":605},{"id":711,"depth":161,"text":712},{"id":752,"depth":147,"text":753},{"id":839,"depth":147,"text":840},{"id":861,"depth":147,"text":862},[531,928,542],"tools","https://i2.wp.com/enricodeleo.s3.eu-south-1.amazonaws.com/images/aquasdk-cover.jpg","2025-03-11T17:00:00.000Z","Come trasformare qualsiasi specifica OpenAPI in un SDK JavaScript intuitivo con sintassi simile a Waterline ORM: la soluzione per integrazioni API veloci e senza boilerplate",{},"/generare-sdk-javascript-waterline-con-aquasdk",{"title":553,"description":931},"generare-sdk-javascript-waterline-con-aquasdk",[544,541,937,938,939],"sdk","rest","developer-tools","77iS9QYVT1OJ4NuE9EjRe48k0fsby1X1WLULVndW9Zg",1782776288773]