CodeWorlds
Powrót do kolekcji
Przewodnik16 min czytaniaZespół CodeWorlds

Fastify, schemat jako źródło prawdy w API

Fastify traktuje schemat JSON jako jedno źródło prawdy dla walidacji, serializacji i dokumentacji. Wersja 5.12.1, hermetyzacja wtyczek i jej koszt.

Fastify, schemat jako źródło prawdy w API

Fastify to framework webowy dla Node, w którym opis danych zapisany jako schemat JSON pełni trzy role naraz: waliduje wejście, buduje funkcję serializującą wyjście i staje się dokumentacją OpenAPI. Bieżąca wersja to 5.12.1 z 18 sierpnia 2026 roku, licencja jest MIT, a pakiet ciągnie za sobą piętnaście zależności produkcyjnych.

Co Fastify właściwie robi

Framework składa się z kilku niezależnych bibliotek spiętych wspólnym interfejsem, a znajomość tego podziału bardzo pomaga przy diagnozowaniu problemów.

Trasowaniem zajmuje się find-my-way, czyli drzewo prefiksowe dopasowujące ścieżkę bez przechodzenia listy wyrażeń regularnych. Walidację obsługuje AJV podłączony przez @fastify/ajv-compiler, który kompiluje każdy schemat do funkcji sprawdzającej raz, przy starcie serwera. Serializację odpowiedzi wykonuje fast-json-stringify, który ze schematu odpowiedzi generuje wyspecjalizowaną funkcję zamiast wywoływać JSON.stringify. Logowanie idzie przez pino. Kolejnością ładowania wtyczek steruje avvio. Testy bez podnoszenia gniazda sieciowego umożliwia light-my-request, wystawiony jako metoda app.inject.

Ten skład tłumaczy, skąd bierze się różnica wobec Express. W Express każda z tych rzeczy jest osobną decyzją: walidację dokłada się jako middleware, serializacja to domyślne JSON.stringify, dokumentacja powstaje w oddzielnym pliku YAML, który po tygodniu przestaje odpowiadać kodowi. W Fastify wszystkie trzy wychodzą z tego samego obiektu schema przypiętego do trasy.

Czego Fastify nie robi, jest równie ważne. Nie ma warstwy dostępu do bazy, więc zapytania pisze się przez Prismę albo dowolny inny sterownik. Nie renderuje interfejsu, bo to teren Next.js. Nie generuje typowanego klienta dla przeglądarki z definicji serwera, co robi tRPC. Nie narzuca struktury katalogów ani wstrzykiwania zależności, w odróżnieniu od NestJS, który zresztą potrafi używać Fastify jako warstwy transportowej.

Wersja, licencja i stan projektu

Rejestr npm podaje dla pakietu fastify wersję 5.12.1 opublikowaną 18 sierpnia 2026 roku, a łączna liczba wydań przekroczyła trzysta dwadzieścia. Wydania mniejsze wychodzą regularnie, co przy głównej wersji piątej oznacza projekt w fazie utrzymania i drobnych ulepszeń, a nie przepisywania.

Licencja jest przypadkiem wzorcowym i akurat tu nie ma czego prostować. Plik LICENSE w repozytorium zawiera tekst MIT z notą „Copyright (c) 2016-present The Fastify team". Pole license w rejestrze npm ma wartość MIT. Opublikowane archiwum fastify-5.12.1.tgz zawiera plik LICENSE obok kodu, więc nawet instalacja bez dostępu do GitHuba daje pełny tekst licencji na dysku. Trzy źródła, jeden wynik. Oficjalne wtyczki z przestrzeni @fastify sprawdzone przy pisaniu tego tekstu, czyli cors, helmet, rate-limit, swagger, swagger-ui, under-pressure i autoload, także deklarują MIT, podobnie jak fastify-plugin i fastify-type-provider-zod.

Jedna rzecz w metadanych zasługuje na uwagę, bo bywa myląca. Plik package.json wersji 5.12.1 nie zawiera pola engines. Menedżer pakietów nie ostrzeże więc przy instalacji na przestarzałym Node, a problem wyjdzie dopiero przy uruchomieniu. Wersję środowiska trzeba pilnować samodzielnie, na przykład przez .nvmrc i sprawdzenie w potoku ciągłej integracji.

Model utrzymania jest jawnie opisany. Opublikowana paczka zawiera pliki GOVERNANCE.md, PROJECT_CHARTER.md, SECURITY.md oraz SPONSORS.md, czyli projekt ma spisane zasady podejmowania decyzji i ścieżkę zgłaszania podatności. Wariantu płatnego ani umowy wsparcia komercyjnego nie ma. To układ typowy dla oprogramowania otwartego i niesie zwykłe ryzyko: tempo napraw zależy od dostępności wolontariuszy, a nie od zobowiązania, które da się wyegzekwować.

Instalacja i pierwszy serwer

Wejście w projekt zajmuje kilka minut, a większość decyzji konfiguracyjnych podejmuje się przy tworzeniu instancji.

Code
Bash
# rdzeń frameworka
npm install fastify

# pomocnik do wtyczek dzielonych między kontekstami
npm install fastify-plugin

# typowe dodatki produkcyjne
npm install @fastify/cors @fastify/helmet @fastify/rate-limit

# generowanie i wystawianie dokumentacji OpenAPI
npm install @fastify/swagger @fastify/swagger-ui

Instancję tworzy się funkcją fabrykującą, a opcje przekazane w tym miejscu obowiązują dla całego serwera.

Code
TypeScript
import Fastify from 'fastify'

const app = Fastify({
  logger: { level: 'info' },
  bodyLimit: 1048576,
  requestIdHeader: 'x-request-id',
  disableRequestLogging: false,
  caseSensitive: true,
  ignoreTrailingSlash: false,
  maxParamLength: 200,
  pluginTimeout: 10000,
  connectionTimeout: 15000,
  keepAliveTimeout: 72000,
  forceCloseConnections: 'idle',
  trustProxy: true,
  ajv: {
    customOptions: {
      removeAdditional: 'all',
      coerceTypes: 'array',
      useDefaults: true,
      allErrors: false
    }
  }
})

app.get('/health', async () => ({ status: 'ok' }))

await app.listen({ port: 3000, host: '0.0.0.0' })

Kilka z tych pól ma niedomyślne konsekwencje. Ustawienie trustProxy włącza odczyt nagłówka x-forwarded-for, co jest konieczne za odwrotnym pośrednikiem, ale niebezpieczne, gdy serwer stoi bezpośrednio w sieci. Wartość forceCloseConnections ustawiona na 'idle' sprawia, że app.close() zamyka bezczynne połączenia utrzymywane przy życiu, bez czego wyłączenie procesu potrafi wisieć aż do końca keepAliveTimeout. Pole pluginTimeout ogranicza czas ładowania pojedynczej wtyczki i jest częstą przyczyną komunikatu o zbyt wolnym starcie, gdy wtyczka czeka na połączenie z bazą.

Opcje removeAdditional, coerceTypes i useDefaults to ustawienia AJV przekazywane przez ajv.customOptions. Pierwsza usuwa pola spoza schematu, druga konwertuje typy, dzięki czemu liczba przekazana w ciągu zapytania przestaje być łańcuchem znaków, a trzecia wstawia wartości domyślne zadeklarowane w schemacie. Pakiet ajv-formats jest zależnością @fastify/ajv-compiler, więc słowo kluczowe format działa bez dodatkowej instalacji.

Schemat jako źródło prawdy

To jest właściwy powód, dla którego ludzie wybierają Fastify. Jeden obiekt opisuje kontrakt trasy i z tego opisu wynikają trzy różne zachowania w czasie działania programu.

Code
TypeScript
app.post('/invoices', {
  schema: {
    tags: ['invoices'],
    body: {
      type: 'object',
      required: ['customerId', 'amount'],
      additionalProperties: false,
      properties: {
        customerId: { type: 'string', format: 'uuid' },
        amount: { type: 'integer', minimum: 1 },
        currency: { type: 'string', enum: ['PLN', 'EUR'], default: 'PLN' },
        note: { type: 'string', maxLength: 500 }
      }
    },
    querystring: {
      type: 'object',
      properties: {
        dryRun: { type: 'boolean', default: false }
      }
    },
    response: {
      201: {
        type: 'object',
        properties: {
          id: { type: 'string' },
          amount: { type: 'integer' },
          currency: { type: 'string' },
          createdAt: { type: 'string' }
        }
      },
      422: {
        type: 'object',
        properties: {
          error: { type: 'string' },
          detail: { type: 'string' }
        }
      }
    }
  }
}, async (request, reply) => {
  const invoice = await app.db.invoice.create({ data: request.body })
  return reply.code(201).send(invoice)
})

Sekcja body odrzuci żądanie z brakującym polem albo z ujemną kwotą, zanim funkcja obsługująca w ogóle się uruchomi. Sekcja querystring zamieni łańcuch "true" na wartość logiczną. Sekcja response jest tą, która zaskakuje najczęściej, bo nie służy do walidacji wyjścia. Fastify kompiluje z niej funkcję serializującą, a wszystko, czego w schemacie nie ma, po prostu nie trafia do odpowiedzi. To działa jak zabezpieczenie przed wyciekiem pól, których nie chcesz wystawiać, i jednocześnie jako pułapka: dodane w bazie pole taxId nie pojawi się w JSON-ie, dopóki nie dopiszesz go do schematu, a żaden błąd o tym nie poinformuje.

Schematy powtarzalne rejestruje się raz i odwołuje przez $ref, co skraca definicje tras i pozwala trzymać kontrakt w jednym miejscu.

Code
TypeScript
app.addSchema({
  $id: 'money',
  type: 'object',
  properties: {
    amount: { type: 'integer' },
    currency: { type: 'string', enum: ['PLN', 'EUR'] }
  }
})

app.get('/invoices/:id/total', {
  schema: {
    params: {
      type: 'object',
      properties: { id: { type: 'string' } }
    },
    response: { 200: { $ref: 'money#' } }
  }
}, async (request) => calculateTotal(request.params.id))

Pisanie schematów JSON ręcznie męczy, zwłaszcza gdy te same kształty istnieją już jako typy w TypeScripcie. Rozwiązaniem jest dostawca typów, który podmienia kompilator walidatora i serializatora, a przy okazji domyka wnioskowanie typu dla request.body.

Code
TypeScript
import { z } from 'zod'
import {
  validatorCompiler,
  serializerCompiler,
  type ZodTypeProvider
} from 'fastify-type-provider-zod'

app.setValidatorCompiler(validatorCompiler)
app.setSerializerCompiler(serializerCompiler)

const typed = app.withTypeProvider<ZodTypeProvider>()

typed.post('/customers', {
  schema: {
    body: z.object({
      email: z.email(),
      plan: z.enum(['free', 'team'])
    }),
    response: {
      201: z.object({ id: z.string(), email: z.email() })
    }
  }
}, async (request, reply) => {
  const customer = await createCustomer(request.body)
  return reply.code(201).send(customer)
})

Pakiet fastify-type-provider-zod w wersji 7.0.0 wymaga Zoda w wersji co najmniej 4.1.5 oraz Fastify w gałęzi 5.5 lub nowszej, a jako zależność równorzędną wskazuje też @fastify/swagger. To wynika wprost z zamysłu: ten sam schemat Zoda ma dawać walidację i wpis w dokumentacji.

Trzecia rola schematu to OpenAPI. Wtyczka @fastify/swagger zbiera schematy wszystkich zarejestrowanych tras i buduje z nich dokument, a @fastify/swagger-ui wystawia go pod wybranym adresem.

Code
TypeScript
await app.register(import('@fastify/swagger'), {
  openapi: {
    info: { title: 'Billing API', version: '1.4.0' },
    servers: [{ url: 'https://api.example.com' }]
  },
  hideUntagged: true
})

await app.register(import('@fastify/swagger-ui'), {
  routePrefix: '/docs',
  uiConfig: { docExpansion: 'list', deepLinking: true },
  staticCSP: true
})

Opcja hideUntagged pomija trasy bez pola tags, co jest wygodnym sposobem trzymania punktów kontrolnych i tras wewnętrznych poza publiczną dokumentacją. Wtyczka pracuje w trybie dynamic, czyli czyta stan serwera, a nie osobny plik, więc dokumentacja nie może się rozjechać z kodem, dopóki schematy są kompletne.

Hermetyzacja wtyczek i jej cena

Drugi filar Fastify jest mniej oczywisty i to on odpowiada za większość pytań początkujących. Wywołanie app.register nie dokłada niczego do wspólnej przestrzeni, tylko tworzy nowy kontekst potomny. Dekoratory, haki i schematy zarejestrowane w tym kontekście widzą jego dzieci, ale nie widzi ich rodzeństwo ani rodzic.

Code
TypeScript
import fp from 'fastify-plugin'
import type { FastifyInstance } from 'fastify'
import { PrismaClient } from '@prisma/client'

async function databasePlugin(app: FastifyInstance) {
  const prisma = new PrismaClient()
  await prisma.$connect()

  app.decorate('db', prisma)
  app.addHook('onClose', async () => {
    await prisma.$disconnect()
  })
}

export default fp(databasePlugin, {
  name: 'db',
  fastify: '5.x'
})

Funkcja fp z pakietu fastify-plugin opakowuje wtyczkę tak, że jej zawartość wychodzi na zewnątrz kontekstu i staje się dostępna w rodzeństwie. Metadane, które przyjmuje, są konkretne: name nadaje nazwę widoczną w drzewie wtyczek i w komunikatach o błędach, fastify deklaruje zakres wersji frameworka, dependencies wymienia nazwy wtyczek, które muszą się załadować wcześniej, decorators wypisuje dekoratory wymagane od otoczenia, a encapsulate pozwala odwrócić działanie i mimo użycia fp zachować hermetyzację.

Reguła praktyczna jest prosta. Wtyczka dostarczająca zasób współdzielony, czyli połączenie z bazą, klienta pamięci podręcznej albo weryfikator tokenów, idzie przez fp. Wtyczka zawierająca trasy i haki właściwe dla jednego obszaru nie potrzebuje fp i lepiej, żeby została zamknięta.

Code
TypeScript
async function invoiceRoutes(app: FastifyInstance) {
  app.decorateRequest('actor', null)

  app.addHook('preHandler', async (request) => {
    request.actor = await resolveActor(request.headers.authorization)
  })

  app.get('/invoices', async (request) => app.db.invoice.findMany())
}

app.register(databasePlugin)
app.register(invoiceRoutes, { prefix: '/api/v1' })
app.register(publicRoutes, { prefix: '/public' })

await app.ready()
console.log(app.printRoutes())
console.log(app.printPlugins())

Hak preHandler zarejestrowany wewnątrz invoiceRoutes obowiązuje wyłącznie w tym kontekście. Trasy z publicRoutes go nie zobaczą, choć obie wtyczki wiszą przy tym samym rodzicu. Ta sama zasada dotyczy uwierzytelniania i to jest najsensowniejszy sposób oddzielenia części chronionej od publicznej: bez tablicy ścieżek wyjętych spod reguły, bez sprawdzania prefiksu w środku middleware.

Teraz o koszcie, bo hermetyzacja jest wadą tak samo jak zaletą. Komunikat o brakującym dekoratorze pojawia się dopiero w czasie działania i mówi tyle, że właściwość jest nieokreślona, a nie że zapomniałeś o fp. Kolejność rejestracji ma znaczenie, więc wtyczka odczytująca dekorator dodany przez inną wtyczkę musi deklarować to przez dependencies, inaczej wynik zależy od kolejności w pliku. Metody printRoutes i printPlugins wywołane po await app.ready() są tu podstawowym narzędziem diagnostycznym i pokazują odpowiednio drzewo tras oraz drzewo kontekstów. Osoba, która pierwszy raz widzi ten model, straci na nim dzień albo dwa, i nie da się tego skrócić samą lekturą dokumentacji.

Drugi koszt to ekosystem. Lista oficjalnych wtyczek @fastify jest przyzwoita i pokrywa uwierzytelnianie, ograniczanie liczby żądań, obsługę plików, sesje, statyczne pliki i nagłówki bezpieczeństwa, ale wciąż jest o rząd wielkości mniejsza niż zbiór middleware napisanych przez lata dla Express. Przy nietypowym wymaganiu, na przykład integracji z leciwym dostawcą tożsamości, prawdopodobieństwo znalezienia gotowego pakietu jest niższe. Istnieją pomosty, @fastify/middie w wersji 9.3.3 dla zwykłego middleware i @fastify/express w wersji 4.0.7 dla pełnej warstwy zgodności, ale każdy z nich odbiera część zysku wydajnościowego i wprowadza obiekty żądania oraz odpowiedzi w kształcie Express.

Cykl życia żądania i haki

Haki to punkty wpięcia w przetwarzanie żądania i ich kolejność jest ustalona. Po dopasowaniu trasy uruchamiane są kolejno onRequest, preParsing, preValidation, preHandler, następnie funkcja obsługująca, a po niej preSerialization, onSend i onResponse. Poza tą ścieżką stoją onError, onTimeout oraz onRequestAbort, wywoływany wtedy, gdy klient zamknie połączenie przed otrzymaniem odpowiedzi.

Code
TypeScript
app.addHook('onRequest', async (request) => {
  request.startedAt = process.hrtime.bigint()
})

app.addHook('onSend', async (request, reply, payload) => {
  const elapsed = Number(process.hrtime.bigint() - request.startedAt) / 1e6
  reply.header('server-timing', `app;dur=${elapsed.toFixed(1)}`)
  return payload
})

app.setErrorHandler((error, request, reply) => {
  if (error.code === 'FST_ERR_VALIDATION') {
    return reply.code(422).send({ error: 'validation_failed', detail: error.message })
  }
  request.log.error({ err: error }, 'unhandled error')
  return reply.code(500).send({ error: 'internal' })
})

app.setNotFoundHandler(async (request, reply) => {
  return reply.code(404).send({ error: 'not_found', path: request.url })
})

Wybór haka wynika z tego, co jest już dostępne. W onRequest ciało żądania nie zostało jeszcze wczytane, więc sprawdzanie tokenu z nagłówka pasuje tu idealnie, a odrzucenie żądania oszczędza pracę parsera. W preValidation ciało istnieje, ale nie przeszło jeszcze walidacji, co jest miejscem na normalizację danych z zewnętrznego systemu. W preHandler masz dane po walidacji i to naturalne miejsce na sprawdzanie uprawnień.

Błędy walidacji dostają kod FST_ERR_VALIDATION i domyślnie kończą się odpowiedzią 400. Jeśli wolisz obsłużyć je w samej trasie zamiast w globalnym uchwycie, ustaw attachValidation: true w opcjach trasy, a Fastify zamiast zgłaszać błąd wpisze go do request.validationError. Haki aplikacyjne to osobna grupa i działają poza cyklem żądania: onReady przed rozpoczęciem nasłuchiwania, onListen po jego rozpoczęciu, onRoute przy każdej rejestrowanej trasie, onRegister przy każdym nowym kontekście, a preClose i onClose przy zamykaniu serwera. Haki żądania również podlegają hermetyzacji, co znaczy, że ten sam kod wpisany o poziom wyżej albo niżej w drzewie wtyczek daje inny zasięg działania.

Fastify a alternatywy

CechaFastifyExpressHonoElysiaNestJS
Walidacja wbudowanatak, schemat JSONbrak, przez middlewareprzez pakiet validatortak, własny system typówtak, przez dekoratory i class-validator
Serializacja ze schematutak, kompilowana funkcjabrakbrakczęściowabrak
Dokumentacja OpenAPIz tego samego schematuz osobnego plikuz pakietu dodatkowegowbudowany modułz dekoratorów
Model rozszerzeńwtyczki z hermetyzacjąmiddleware globalnemiddleware łańcuchowewtyczkimoduły i wstrzykiwanie
Środowisko uruchomienioweserwer HTTP Nodeserwer HTTP Nodewiele, oparte o Fetch APIgłównie BunNode, transport wymienny
Bieżąca wersja5.12.15.2.14.13.31.4.2911.2.1
LicencjaMITMITMITMITMIT

Wybór rozstrzyga się na kilku pytaniach. Jeśli budujesz API, którego kontrakt ma być pilnowany maszynowo i wystawiany jako OpenAPI, Fastify daje to najmniejszym nakładem. Jeśli celem jest funkcja brzegowa albo pracownik w środowisku opartym o Fetch API, sięgnij po Hono, bo Fastify stoi na module HTTP z Node i tam nie pojedzie. Jeśli pracujesz w Bun i chcesz wnioskowania typów bez osobnego dostawcy, rozważ Elysię, pamiętając, że jej społeczność jest wyraźnie mniejsza. Jeśli klientem API jest wyłącznie Twój własny frontend w TypeScripcie, tRPC usuwa cały problem kontraktu, ale zamyka Cię w jednym języku po obu stronach. A jeśli zespół jest duży i potrzebuje narzuconej struktury, NestJS daje ją wprost i potrafi działać na adapterze Fastify, łącząc oba podejścia.

Express pozostaje sensownym wyborem w dwóch sytuacjach: gdy projekt już na nim stoi i nie ma problemu wydajnościowego, oraz gdy zależysz od middleware bez odpowiednika w ekosystemie Fastify. Migracja z Express w praktyce zawsze wymaga przepisania warstwy middleware, bo interfejsy żądania i odpowiedzi się różnią.

Typowe błędy

Pierwszy to zdziwienie znikającymi polami. Schemat response nie sprawdza odpowiedzi, tylko ją buduje, więc pole nieobecne w schemacie nie trafi do wyniku i nie pojawi się żadne ostrzeżenie. Za każdym razem, gdy dokładasz pole do modelu, dopisz je też do schematu.

Drugi to dekorator ustawiony w zwykłej wtyczce zamiast we wtyczce opakowanej przez fp. Połączenie z bazą przypięte przez app.decorate wewnątrz zwykłej funkcji istnieje tylko w jej kontekście, a rodzeństwo zobaczy wartość nieokreśloną. Objaw wygląda jak błąd w kolejności ładowania, a przyczyną jest hermetyzacja.

Trzeci to jednoczesne użycie return i reply.send w funkcji asynchronicznej. Zwrócenie wartości z funkcji async samo wysyła odpowiedź, więc wcześniejsze reply.send powoduje próbę wysłania jej dwa razy. Wybierz jedną konwencję i trzymaj się jej w całym projekcie.

Czwarty to liczby przychodzące z ciągu zapytania jako łańcuchy znaków. Bez schematu dla querystring albo bez coerceTypes w opcjach AJV parametr ?page=2 zostanie łańcuchem, a porównanie z liczbą da fałsz. To najczęstsza przyczyna dziwnego stronicowania.

Piąty to rejestrowanie tras po wywołaniu listen. Fastify domyka drzewo wtyczek przy starcie, więc trasa dodana później zostanie odrzucona. Cała konfiguracja musi wykonać się wcześniej, a jeśli potrzebujesz asynchronicznego przygotowania, użyj await app.ready().

Szósty to trustProxy włączone bez pośrednika przed serwerem. W takim układzie klient może podać dowolny adres w nagłówku x-forwarded-for i obejść ograniczanie liczby żądań oparte o adres źródłowy.

Siódmy to poleganie na menedżerze pakietów w kwestii wersji Node. Pakiet fastify w wersji 5.12.1 nie deklaruje pola engines, więc instalacja na starym środowisku przejdzie bez słowa, a serwer wywali się dopiero przy uruchomieniu.

FAQ

Czy Fastify jest naprawdę szybszy od Express?

Różnica bierze się z trzech konkretnych mechanizmów, a nie z ogólnej optymalizacji. Trasowanie idzie po drzewie prefiksowym zamiast po liście dopasowań. Walidacja i serializacja są kompilowane raz przy starcie do wyspecjalizowanych funkcji, więc w czasie żądania nie ma refleksji nad schematem. Wielkość zysku zależy jednak od kształtu odpowiedzi i od tego, ile czasu zajmuje baza danych. Zmierz na własnym obciążeniu, zanim uznasz framework za wąskie gardło.

Czy muszę pisać schematy JSON ręcznie?

Nie. Dostawca typów podmienia kompilator walidatora i serializatora, dzięki czemu schematy piszesz w Zodzie, a Fastify korzysta z nich tak samo jak ze schematów JSON. Pakiet fastify-type-provider-zod w wersji 7.0.0 wymaga Zoda 4.1.5 lub nowszego i Fastify z gałęzi 5.5 wzwyż. Kosztem jest dodatkowa zależność i to, że schemat OpenAPI powstaje z konwersji, a nie bezpośrednio.

Czy Fastify uruchomi się na brzegu sieci albo w Bun?

Fastify buduje się na module HTTP z Node, a nie na Web Fetch API, więc środowiska brzegowe oparte o standard Fetch nie są jego terenem i tam sięga się po Hono. Bun oferuje warstwę zgodności z API Node, ale to inny scenariusz niż framework pisany pod to środowisko od początku, jak Elysia.

Czy da się przenieść middleware z Express?

Częściowo. Wtyczka @fastify/middie w wersji 9.3.3 pozwala używać funkcji middleware o sygnaturze z trzema argumentami, a @fastify/express w wersji 4.0.7 daje szerszą warstwę zgodności. Obie dokładają narzut i wprowadzają obiekty w kształcie Express, więc traktuj je jako etap migracji, a nie stan docelowy.

Czy Fastify jest płatny?

Nie. Cały projekt jest na licencji MIT, potwierdzonej w pliku LICENSE w repozytorium, w polu license rejestru npm oraz plikiem licencyjnym wewnątrz opublikowanego archiwum. Nie ma wariantu komercyjnego ani płatnego wsparcia, a rozwój finansują sponsorzy wymienieni w pliku SPONSORS.md.

Dokumentację znajdziesz na stronie Fastify, spis oficjalnych wtyczek w dziale ekosystemu, a kod źródłowy w repozytorium na GitHubie.

Czytaj dalej

Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie