Gathering detailed insights and metrics for @patrick115/sveltekitapi
Gathering detailed insights and metrics for @patrick115/sveltekitapi
Gathering detailed insights and metrics for @patrick115/sveltekitapi
Gathering detailed insights and metrics for @patrick115/sveltekitapi
npm install @patrick115/sveltekitapi
Typescript
Module System
Node Version
NPM Version
TypeScript (90.75%)
Svelte (6.24%)
JavaScript (2.38%)
HTML (0.63%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
79 Commits
1 Watchers
1 Branches
1 Contributors
Updated on May 08, 2025
Latest Version
1.2.16
Package Id
@patrick115/sveltekitapi@1.2.16
Unpacked Size
60.05 kB
Size
13.08 kB
File Count
21
NPM Version
10.9.2
Node Version
22.14.0
Published on
May 08, 2025
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
Package for creating SvelteKit API endpoints with typesafe routes and client.
This package is highly inspired by TRPC's structure.
First step is creating new API with your context, which will be accesible in every procedure and middleware. Also you can export router and basic procedure.
src/lib/server/api.ts
1 2import { APICreate } from '@patrick115/sveltekitapi' 3import type { Context } from './context' 4 5export const api = new APICreate<Context>() 6 7export const router = api.router 8export const procedure = api.procedure 9
Here you can create your context, which get called on every request and get passed SvelteKit's RequestEvent.
src/lib/server/context.ts
1import type { AsyncReturnType, CreateContext } from '@patrick115/sveltekitapi' 2 3export const context = (async (ev /*<- SvelteKit's RequestEvent */) => { 4 return {} // Here you can put your context 5}) satisfies CreateContext 6 7export type Context = AsyncReturnType<typeof context>
Now we create router and pass object to it with our procedures. In each procedure we can specify HTTP method (GET, POST, PUT, DELETE, PATCH). For methods other than GET we can specify input schema with .input(ZodSchema). Then we specify what to do with the request with .query(). Parameters for query function are: context, input (in case of method other than GET), and ev, which is RequestEvent from SvelteKit in case you need to set cookies, or get user's ip or access the raw request.
src/lib/server/routes.ts
1import { json } from '@sveltejs/kit' 2import { z } from 'zod' 3import { postProcedure, proc2, procedure, router } from './api' 4 5export const r = router({ 6 example: procedure.GET.query(() => { 7 return 'Hello from the API!' 8 }), 9}) 10 11export type AppRouter = typeof r
At the end we create server and pass in the router, path to API and context.
src/lib/server/server.ts
1import { APIServer } from '@patrick115/sveltekitapi' 2import { context } from './context' 3import { r } from './routes' 4 5export const Server = new APIServer({ 6 router: r, 7 path: '/api', 8 context 9})
If we want to use our API in SvelteKit's endpoint we can do it like this: (export const for each method you want to use, in this case GET, POST, PUT, DELETE, PATCH)
src/routes/api/[...data]/+server.ts
1import { Server } from '$/lib/server/server' 2 3export const GET = Server.handler 4export const POST = Server.handler 5export const PUT = Server.handler 6export const DELETE = Server.handler 7export const PATCH = Server.handler 8
Now syncing with frontend
First we create an API client. As type we pass our router type and as parameter we pass rootPath for our API (same as in server).
src/lib/api.ts
1import { createAPIClient } from '@patrick115/sveltekitapi' 2import type { AppRouter } from './server/routes' 3 4export const API = createAPIClient<AppRouter>('/api') 5
Syncing with frontend. From load function we return object with our object returned from Server.hydrateToClient() function.
src/routes/+layout.server.ts
1import { Server } from '$/lib/server/server' 2import type { LayoutServerLoad } from './$types' 3 4export const load = (async () => { 5 return { 6 api: Server.hydrateToClient() 7 } 8}) satisfies LayoutServerLoad
Now we need to pass this object to our client
src/routes/+layout.svelte
1<script lang="ts"> 2 import { API } from '$/lib/api'; 3 import type { Snippet } from 'svelte'; 4 import type { LayoutData } from './$types'; 5 6 let { children, data }: { children: Snippet; data: LayoutData } = $props(); 7 8 API.hydrateFromServer(data.api); 9</script> 10 11{@render children()}
Now we can call our API from our frontend
src/routes/+page.svelte
1<script lang="ts"> 2 import { API } from '$/lib/api'; 3 import { onMount } from 'svelte'; 4 5 onMount(async () => { 6 const res = await API.example(); 7 console.log(res); 8 }); 9</script> 10 11<h1>Hello from SvelteKit!</h1>
1#npm 2npm install @patrick115/sveltekitapi 3 4#pnpm 5pnpm install @patrick115/sveltekitapi 6 7#yarn 8yarn add @patrick115/sveltekitapi
Context is a function that gets called on every request and returns object with data that will be accesible in every procedure and middleware. It gets passed SvelteKit's RequestEvent.
Example of passing user's IP and session cookie to every procedure and middleware.
1import type { AsyncReturnType, CreateContext } from '@patrick115/sveltekitapi' 2 3export const context = (async (ev) => { 4 const ip = ev.getClientAddress() 5 const cookie = ev.cookies.get("session") 6 return { 7 cookie, 8 ip 9 } 10}) satisfies CreateContext 11 12export type Context = AsyncReturnType<typeof context>
Middleware is a function that gets called before every request on procedure, that uses that middleware. It gets passed context, input (with unknown type, because it can be used on multiple endpoints with multiple methods. In case of GET method, input contains undefined), SvelteKit's RequestEvent and next function, which is used to call next middleware or procedure. You need to call this function at the end of your middleware and return its result. You can pass new context as next function's parameter.
Example of middleware that checks if user is logged in and if not, it returns error.
1import { MiddleWareError } from '@patrick115/sveltekitapi'
2
3export const procedure = api.procedure
4
5export const securedProcedure = procedure.use(async ({ctx, next}) => {
6 if (!ctx.cookie) {
7 throw new MiddleWareError({
8 status: 401,
9 message: 'You need to be logged in to access this endpoint.'
10 })
11 }
12
13 const data = jwt.getCookie<User>(ctx.cookie)
14
15 if (!data) {
16 throw new MiddleWareError({
17 status: 401,
18 message: 'You need to be logged in to access this endpoint.'
19 })
20 }
21
22 return next({
23 ...ctx, //note, that context will be overwritten with new context, so if you want to pass some data from old context, you need to pass it here
24 user: data
25 })
26})
In router we can define procedures, each procedure can have each HTTP method (GET, POST, PUT, DELETE, PATCH). For methods other than GET we can specify input schema with .input(ZodSchema). Then we specify what to do with the request with .query(). Parameters for query function are: context, input (in case of method other than GET), and ev, which is RequestEvent from SvelteKit in case you need to set cookies, or get user's ip or access the raw request.
Note: if some procedure implements some middleware, return type will be ErrorApiResponse | your returned type, since you can throw error from middleware.
Example of procedure that returns Hello World.
1 2import { procedure, router } from './api' 3 4export const r = router({ 5 example: procedure.GET.query(() => { 6 return `Hello world` as const 7 }) 8}) 9 10export type AppRouter = typeof r
Calling this procedure from frontend.
1const data = await API.example() 2console.log(data) //Hello world 3// ^? data: "Hello world" 4//Note, if this procedure would implement some middleware, return type would be ErrorApiResponse | "Hello world"
Multiple HTTP methods on one endpoint.
1import { z } from 'zod' 2import { procedure, router } from './api' 3 4export const r = router({ 5 example: [ 6 procedure.GET.query(() => { 7 return `Hello world` as const 8 }), 9 procedure.POST.input( 10 z.object({ 11 username: z.string() 12 }) 13 ).query(({ input }) => { 14 return `Hello ${input.username}` as const 15 }) 16 ] 17}) 18 19export type AppRouter = typeof r
Calling this procedure from frontend.
1const data = await API.example.GET() //here we can see, that we need to select which method we want to call 2console.log(data) 3// ^? data: "Hello world" 4 5const data2 = await API.example.POST({ 6 username: 'Patrik' 7}) 8console.log(data2) 9// ^? data: "Hello ${string}"
Procedure with FormData as input
1import { FormDataInput } from '@patrick115/sveltekitapi' 2import { procedure, router } from './api' 3 4export const r = router({ 5 example: procedure.POST.input(FormDataInput).query(({ input }) => { 6 const name = input.get('name') 7 return `Hello ${name ?? 'World'}` as const 8 }) 9}) 10 11 12export type AppRouter = typeof r 13
Calling this procedure from frontend.
1const formData = new FormData() 2formData.append("name", "Patrik) 3 4const data = await API.example(formData) 5console.log(data) //Hello Patrik 6// ^? data: "Hello ${string}"
Extending endpoint with sub routes
1import { z } from 'zod' 2import { procedure, router } from './api' 3 4export const r = router({ 5 example: [ 6 procedure.GET.query(() => { 7 return `Hello world` as const 8 }), 9 procedure.POST.input( 10 z.object({ 11 username: z.string() 12 }) 13 ).query(({ input }) => { 14 return `Hello ${input.username}` as const 15 }), 16 //Subroutes, but only single sub-object is supported 17 { 18 // /api/example/hello 19 20 hello: procedure.GET.query(() => { 21 return "Hello World, again" as const 22 }) 23 } 24 ] 25}) 26 27export type AppRouter = typeof r
Calling this procedure from frontend.
1const data = await API.example.GET() //here we can see, that we need to select which method we want to call 2console.log(data) 3// ^? data: "Hello world" 4 5const data2 = await API.example.POST({ 6 username: 'Patrik' 7}) 8console.log(data2) 9// ^? data: "Hello ${string}" 10 11const data3 = await API.example.hello() 12console.log(data3) 13// ^? data: "Hello World, again"
If you want to render some data from your API on server side, you can use Server.ssr object. This object contains similar structure as API object. Only difference is, that it doesn't make the fetch request, but directly call the function, since its in same memory space. Also because direct calling, you cannot get context of the request, you need to pass it as first parameter. GET method now requres 1 argument instead of 0, and other methods 2 arguments instead of 1. First argument is context and second is input.
For example I have the example route with GET and POST method. I can call it like this in server side render:
+page.server.ts
1export const load = (async (event) => { 2 const data = await API.example.GET(event) 3 const data2 = await API.example.POST(event, { username: 'Patrik' }) 4 return { 5 data, 6 data2 7 } 8}) satisfies PageServerLoad
now can we access this data on our page:
1<script lang="ts"> 2 import type { PageProps } from './$types' 3 4 const { data }: PageProps = $props(); 5 6 console.log(data) //Hello world 7 console.log(data2) //Hello Patrik 8</script> 9<h1>Hello from SvelteKit!</h1>
SvelteKit also have something called actions, which are used to handle form submissions. More on that here
We can use our API in actions as well. The input type of procedure should be FormDataInput, and technically the Method doesn't matter, but preffer the POST.
Then you can use the Server.actions
object to call the procedure. It have the similar structure to API object, or Server.ssr object, but is used for actions only.
The example will also use the use:enhance
which simply means, that if we have JavaScript in browser, instead of reloading the page, it will send the request to the action and update the form
object with the response.
First we will create our route:
1export const r = router({ 2 form: procedure.POST.input(FormDataInput).query(({ input }) => { 3 const name = input.get('name') 4 return `Hello ${name ?? 'World'}` as const 5 }), 6})
We don't account for previous context, just for simplicity we have a new router with only one route called form
.
Now we create our action:
1import { Server } from '$/lib/server/server'; 2import type { Actions } from '@sveltejs/kit'; 3 4export const actions = { 5 default: Server.actions.form 6} satisfies Actions
now we create our form with enhance:
1<script lang="ts"> 2 import type { PageProps } from './$types' 3 import { enhance } from '$app/forms' 4 5 const { form }: PageProps = $props(); 6</script> 7{JSON.stringify(form)} //Before submit it will be `null`and after submit it will be `{"name":"Patrik"}` 8 9<form method="POST" use:enhance> 10 <input type="text" name="name" /> <!-- for example we enter here "Patrik" --> 11 <button type="submit">Submit</button> <!-- And then we submit !--> 12</form>
No vulnerabilities found.
No security vulnerabilities found.