jsonServer-Routen sind ein mächtiges Feature von TanStack Start, das es Ihnen ermöglicht, serverseitige Endpunkte in Ihrer Anwendung zu erstellen. Sie sind nützlich für die Verarbeitung von rohen HTTP-Anfragen, Formularübermittlungen, Benutzerauthentifizierung und vieles mehr.
Server-Routen können in Ihrem ./src/routes-Verzeichnis Ihres Projekts definiert werden, direkt neben Ihren TanStack Router-Routen und werden automatisch vom TanStack Start-Server verarbeitet.
Hier ist, wie eine einfache Server-Route aussieht
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return new Response('Hello, World!')
},
})
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return new Response('Hello, World!')
},
})
Da Server-Routen im selben Verzeichnis wie Ihre App-Routen definiert werden können, können Sie sogar dieselbe Datei für beides verwenden!
// routes/hello.tsx
export const ServerRoute = createServerFileRoute().methods({
POST: async ({ request }) => {
const body = await request.json()
return new Response(JSON.stringify({ message: `Hello, ${body.name}!` }))
},
})
export const Route = createFileRoute('/hello')({
component: HelloComponent,
})
function HelloComponent() {
const [reply, setReply] = useState('')
return (
<div>
<button
onClick={() => {
fetch('/hello', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: 'Tanner' }),
})
.then((res) => res.json())
.then((data) => setReply(data.message))
}}
>
Say Hello
</button>
</div>
)
}
// routes/hello.tsx
export const ServerRoute = createServerFileRoute().methods({
POST: async ({ request }) => {
const body = await request.json()
return new Response(JSON.stringify({ message: `Hello, ${body.name}!` }))
},
})
export const Route = createFileRoute('/hello')({
component: HelloComponent,
})
function HelloComponent() {
const [reply, setReply] = useState('')
return (
<div>
<button
onClick={() => {
fetch('/hello', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: 'Tanner' }),
})
.then((res) => res.json())
.then((data) => setReply(data.message))
}}
>
Say Hello
</button>
</div>
)
}
Server-Routen in TanStack Start folgen denselben dateibasierten Routing-Konventionen wie TanStack Router. Das bedeutet, dass jede Datei in Ihrem routes-Verzeichnis mit einem ServerRoute-Export als API-Route behandelt wird. Hier sind einige Beispiele:
Jede Route kann nur eine einzige Handler-Datei zugeordnet haben. Wenn Sie also eine Datei namens routes/users.ts haben, die dem Anfragepfad von /users entspricht, können Sie keine anderen Dateien haben, die ebenfalls zur selben Route aufgelöst werden. Zum Beispiel würden die folgenden Dateien alle zur selben Route aufgelöst werden und zu einem Fehler führen:
Genau wie bei normalen Routen können Server-Routen auf escapte Zeichen abgestimmt werden. Beispielsweise erstellt eine Datei namens routes/users[.]json.ts eine API-Route unter /users.json.
Aufgrund des einheitlichen Routing-Systems werden pfadlose Layout-Routen und Break-out-Routen für ähnliche Funktionalitäten rund um Server-Routen-Middleware unterstützt.
In den obigen Beispielen haben Sie vielleicht bemerkt, dass die Namenskonventionen für Dateien flexibel sind und es Ihnen ermöglichen, Verzeichnisse und Dateinamen zu mischen und anzupassen. Dies ist beabsichtigt und ermöglicht es Ihnen, Ihre Server-Routen so zu organisieren, wie es für Ihre Anwendung sinnvoll ist. Mehr dazu erfahren Sie im TanStack Router File-based Routing Guide.
Server-Routen-Anfragen werden von Starts createStartHandler in Ihrer server.ts-Einstiegsdatei verarbeitet.
// server.ts
import {
createStartHandler,
defaultStreamHandler,
} from '@tanstack/solid-start/server'
import { createRouter } from './router'
export default createStartHandler({
createRouter,
})(defaultStreamHandler)
// server.ts
import {
createStartHandler,
defaultStreamHandler,
} from '@tanstack/solid-start/server'
import { createRouter } from './router'
export default createStartHandler({
createRouter,
})(defaultStreamHandler)
Der Start-Handler ist dafür verantwortlich, eine eingehende Anfrage einer Server-Route zuzuordnen und die entsprechende Middleware und den Handler auszuführen.
Denken Sie daran, wenn Sie den Server-Handler anpassen müssen, können Sie dies tun, indem Sie einen benutzerdefinierten Handler erstellen und dann das Event an den Start-Handler übergeben
// server.ts
import { createStartHandler } from '@tanstack/solid-start/server'
export default defineHandler((event) => {
const startHandler = createStartHandler({
createRouter,
})(defaultStreamHandler)
return startHandler(event)
})
// server.ts
import { createStartHandler } from '@tanstack/solid-start/server'
export default defineHandler((event) => {
const startHandler = createStartHandler({
createRouter,
})(defaultStreamHandler)
return startHandler(event)
})
Server-Routen werden erstellt, indem ein ServerRoute aus einer Routendatei exportiert wird. Der ServerRoute-Export sollte durch Aufrufen der Funktion createServerFileRoute erstellt werden. Das resultierende Builder-Objekt kann dann verwendet werden, um
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
},
})
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
},
})
Es gibt zwei Möglichkeiten, einen Handler für eine Server-Route zu definieren.
Für einfache Anwendungsfälle können Sie eine Handler-Funktion direkt für die Methode bereitstellen.
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
},
})
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
},
})
Für komplexere Anwendungsfälle können Sie eine Handler-Funktion über das Methoden-Builder-Objekt bereitstellen. Dies ermöglicht es Ihnen, der Methode Middleware hinzuzufügen.
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods((api) => ({
GET: api.middleware([loggerMiddleware]).handler(async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
}),
}))
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods((api) => ({
GET: api.middleware([loggerMiddleware]).handler(async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
}),
}))
Jeder Handler für eine HTTP-Methode erhält ein Objekt mit folgenden Eigenschaften:
Nachdem Sie die Anfrage verarbeitet haben, können Sie ein Response-Objekt oder Promise<Response> zurückgeben oder sogar eine der Hilfsfunktionen von @tanstack/solid-start verwenden, um die Antwort zu bearbeiten.
Server-Routen unterstützen dynamische Pfadparameter auf die gleiche Weise wie TanStack Router. Beispielsweise erstellt eine Datei namens routes/users/$id.ts eine API-Route unter /users/$id, die einen dynamischen id-Parameter akzeptiert.
// routes/users/$id.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ params }) => {
const { id } = params
return new Response(`User ID: ${id}`)
},
})
// Visit /users/123 to see the response
// User ID: 123
// routes/users/$id.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ params }) => {
const { id } = params
return new Response(`User ID: ${id}`)
},
})
// Visit /users/123 to see the response
// User ID: 123
Sie können auch mehrere dynamische Pfadparameter in einer einzigen Route haben. Zum Beispiel erstellt eine Datei namens routes/users/$id/posts/$postId.ts eine API-Route unter /users/$id/posts/$postId, die zwei dynamische Parameter akzeptiert.
// routes/users/$id/posts/$postId.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ params }) => {
const { id, postId } = params
return new Response(`User ID: ${id}, Post ID: ${postId}`)
},
})
// Visit /users/123/posts/456 to see the response
// User ID: 123, Post ID: 456
// routes/users/$id/posts/$postId.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ params }) => {
const { id, postId } = params
return new Response(`User ID: ${id}, Post ID: ${postId}`)
},
})
// Visit /users/123/posts/456 to see the response
// User ID: 123, Post ID: 456
Server-Routen unterstützen auch Wildcard-Parameter am Ende des Pfades, die durch ein $ gefolgt von nichts gekennzeichnet sind. Zum Beispiel erstellt eine Datei namens routes/file/$.ts eine API-Route unter /file/$, die einen Wildcard-Parameter akzeptiert.
// routes/file/$.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ params }) => {
const { _splat } = params
return new Response(`File: ${_splat}`)
},
})
// Visit /file/hello.txt to see the response
// File: hello.txt
// routes/file/$.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ params }) => {
const { _splat } = params
return new Response(`File: ${_splat}`)
},
})
// Visit /file/hello.txt to see the response
// File: hello.txt
Um POST-Anfragen zu verarbeiten, können Sie einen POST-Handler zum Routenobjekt hinzufügen. Der Handler erhält das Request-Objekt als erstes Argument, und Sie können auf den Request-Body über die Methode request.json() zugreifen.
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
POST: async ({ request }) => {
const body = await request.json()
return new Response(`Hello, ${body.name}!`)
},
})
// Send a POST request to /hello with a JSON body like { "name": "Tanner" }
// Hello, Tanner!
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
POST: async ({ request }) => {
const body = await request.json()
return new Response(`Hello, ${body.name}!`)
},
})
// Send a POST request to /hello with a JSON body like { "name": "Tanner" }
// Hello, Tanner!
Dies gilt auch für andere HTTP-Methoden wie PUT, PATCH und DELETE. Sie können Handler für diese Methoden im Routenobjekt hinzufügen und über die entsprechende Methode auf den Request-Body zugreifen.
Es ist wichtig zu beachten, dass die Methode request.json() ein Promise zurückgibt, das zu dem geparsten JSON-Body der Anfrage aufgelöst wird. Sie müssen das Ergebnis awaiten, um auf den Body zuzugreifen.
Dies ist ein gängiges Muster für die Verarbeitung von POST-Anfragen in Server-Routen. Sie können auch andere Methoden wie request.text() oder request.formData() verwenden, um auf den Body der Anfrage zuzugreifen.
Beim Zurückgeben von JSON mit einem Response-Objekt ist dies ein gängiges Muster:
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return new Response(JSON.stringify({ message: 'Hello, World!' }), {
headers: {
'Content-Type': 'application/json',
},
})
},
})
// Visit /hello to see the response
// {"message":"Hello, World!"}
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return new Response(JSON.stringify({ message: 'Hello, World!' }), {
headers: {
'Content-Type': 'application/json',
},
})
},
})
// Visit /hello to see the response
// {"message":"Hello, World!"}
Oder Sie können die Hilfsfunktion json verwenden, um den Content-Type-Header automatisch auf application/json zu setzen und das JSON-Objekt für Sie zu serialisieren.
// routes/hello.ts
import { json } from '@tanstack/solid-start'
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return json({ message: 'Hello, World!' })
},
})
// Visit /hello to see the response
// {"message":"Hello, World!"}
// routes/hello.ts
import { json } from '@tanstack/solid-start'
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return json({ message: 'Hello, World!' })
},
})
// Visit /hello to see the response
// {"message":"Hello, World!"}
Sie können den Statuscode der Antwort festlegen, indem Sie entweder:
Ihn als Eigenschaft des zweiten Arguments für den Response-Konstruktor übergeben
// routes/hello.ts
import { json } from '@tanstack/solid-start'
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request, params }) => {
const user = await findUser(params.id)
if (!user) {
return new Response('User not found', {
status: 404,
})
}
return json(user)
},
})
// routes/hello.ts
import { json } from '@tanstack/solid-start'
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request, params }) => {
const user = await findUser(params.id)
if (!user) {
return new Response('User not found', {
status: 404,
})
}
return json(user)
},
})
Die Hilfsfunktion setResponseStatus von @tanstack/solid-start/server verwenden
// routes/hello.ts
import { json } from '@tanstack/solid-start'
import { setResponseStatus } from '@tanstack/solid-start/server'
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request, params }) => {
const user = await findUser(params.id)
if (!user) {
setResponseStatus(404)
return new Response('User not found')
}
return json(user)
},
})
// routes/hello.ts
import { json } from '@tanstack/solid-start'
import { setResponseStatus } from '@tanstack/solid-start/server'
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request, params }) => {
const user = await findUser(params.id)
if (!user) {
setResponseStatus(404)
return new Response('User not found')
}
return json(user)
},
})
In diesem Beispiel geben wir einen Statuscode von 404 zurück, wenn der Benutzer nicht gefunden wird. Sie können jeden gültigen HTTP-Statuscode mit dieser Methode festlegen.
Manchmal müssen Sie Header in der Antwort setzen. Sie können dies tun, indem Sie entweder:
Ein Objekt als zweites Argument für den Response-Konstruktor übergeben.
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return new Response('Hello, World!', {
headers: {
'Content-Type': 'text/plain',
},
})
},
})
// Visit /hello to see the response
// Hello, World!
// routes/hello.ts
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
return new Response('Hello, World!', {
headers: {
'Content-Type': 'text/plain',
},
})
},
})
// Visit /hello to see the response
// Hello, World!
Oder die Hilfsfunktion setHeaders von @tanstack/solid-start/server verwenden.
// routes/hello.ts
import { setHeaders } from '@tanstack/solid-start/server'
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
setHeaders({
'Content-Type': 'text/plain',
})
return new Response('Hello, World!')
},
})
// routes/hello.ts
import { setHeaders } from '@tanstack/solid-start/server'
export const ServerRoute = createServerFileRoute().methods({
GET: async ({ request }) => {
setHeaders({
'Content-Type': 'text/plain',
})
return new Response('Hello, World!')
},
})
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.