2. Frontend - Refzlund/sveltekit-zero-api GitHub Wiki

Accessing endpoint in the front-end

Note: Run  npm run dev  to generate  api.ts

Types are generated when the server is running, so if a type isn't there. Edge-case; start/restart the dev server.

On the front-end you can access your api by importing it, and it will have type-safety all the way.

api.ts - Accessing your endpoint

import api from '$src/api'

api.ts is a generated file by Zero API. It will include the type and functions for the whole operation. If we have src/routes/api/products/+server.ts as an endpoint with a POST, we can access it as api.products.POST

Request Parameters

The api will automatically pick up the paramters for the endpoint. Intellisense with API calls

Awaited promise

If you await an api function such as api.products.GET(), you will get a Response (unless you're using .$.).

let response = await api.products.GET()
if(response.status == 200)
   console.log(response.body)

// eqv. to

api.products.GET().ok(r => console.log(r.body))

Slugs

If you have a route like
src/routes/api/products/[warehouse]/storage/[product]/+server.ts

You can access this by using

api.products.warehouse$('austin-warehouse').storage.product$(productId).GET()

In SvelteKit, the load functions has its own fetch which you can pass to the api.

If running an api call on the client and server, without providing a fetch function as the second argument — the api will only be called on the client.

import type { PageLoad } from './$types'

export const load: PageLoad = async ({ params, fetch }) => {
   const { id } = params

   // Pass `fetch` as the second argument
   const response = await api.products.id$(id).GET({}, fetch)

   return {
      status: response.status,
      props: {
        product: response.ok && response.body
      }
   }
}

Callbacks

For every response in your endpoint, there will be a callback function. If your backend returns

return Ok({ body: { message: 'Hello there' } })

Then you can access it doing:

api.product.GET().ok(response => { console.log(response.body.message) })

Every response-code has their own callback

Ok: 200            // .Ok(response => )
BadRequest: 400    // .BadRequest(response => ) 
InternalError: 500 // .InternalError(response => )

And some callbacks cover more:

Any: xxx           // .Any(r => )
Informational: 1xx // .Informational(r => )
Success: 2xx       // .Success(r => )
Redirect: 3xx      // .Redirect(r => )
ClientError: 4xx   // .ClientError(r => )
ServerError: 5xx   // .ServerError(r => )
Error: 4xx or 5xx  // .Error(r => )

The types in the backend are available in the frontend

if(A)
   return Ok({ body: { message: 'Hello there', lol: false } })
else
   return Created({ body: { message: 'Message created', product: someProduct, lol: true } })

// Side-note: Any Error response (4xx/5xx), have { error: string, target: any }
// as optional options. They will be in response: { body: { error, target } }

// If error isn't populated, the error message will be it's name f.i. "error: 'Internal Error'"
return InternalError({ error: 'Something went wrong' })

Here you'll find the types:

api.product.GET()
   // { body: { message: string, lol: boolean }, ... }
   .Ok(response => {
      const {
         message, 
         product,lol 
      } = response.body
   }) 
   // { body: { message: string, product: ProductType, lol: boolean }, ... }
   .Created(({ body }) => {
      const { 
         message, 
         product,lol 
      } = body
   }) 
   // { body: { error: string }, ... }
   .InternalError(r => console.error(r.body.error)) 
   .Success(r => {
      let body = r.body
      
      // All Success responses have { body: { message: string } }
      body.message 
      // Not all have product
      body.product 

      if(!('product' in body)) // Return if 'product'-key is not in body
         return
      
      // Because we checked if product is in body, it is now valid
      body.product 
   })

These functions will also be called in order. So

  1. Ok
  2. Success

or

  1. Created
  2. Success

In case of 200 (Ok) or 201 (Created)


._. (underscore)

If an endpoint does not return a status-code, but you still want a callback use ._. wildcard:

api.product.GET()._.UnavailableForLegalReasons(handleError)

.$. (dollar)

An exception to getting a Promise<Response>, is using the wildcard .$.

This returns whatever is returned from the trailing callback. Naturally, only one is allowed. And is only allowed in the end of the function. If the return isn't an Ok, then it returns undefined.

// products: Product[] | undefined
let products = await api.product.GET().$.Ok(r => r.body)
if(!products) {
   console.error('Did not receive any products.')
   return
}

Assigning variables directly


Accessing types

import type { ResponseBody, RequestParams } from 'sveltekit-zero-api/helpers'

ResponseBody gets the body of a response, for a specific status-code.

           // Where response: { body: { products: Product[] } }
let products: ResponseBody<typeof api.products.GET, 'Ok'>['products']

let productParams: RequestParams<typeof api.products.POST> = {
   body: { productName: 'Banana' },
   query: { value: 69.101 }
}
⚠️ **GitHub.com Fallback** ⚠️