Solid & @solidjs/router & SolidStart
Solid has an advantage of being a later stage framework, which could observe which patterns worked and more importantly which didn’t from it’s older bretheren.
This allows solid-js
to present a united front when it comes to data fetching and essentially export a single function that works on both server and client.
Setup
First here’s an example api router definition.
import { api } from '@hulla/api'
import { db } from '../db'
const a = api()
export const usersAPI = a.router({
name: 'users',
routes: [
a.procedure('getUserById', (id: string) => db.users.get(id)),
a.procedure('createUser', (user: User) => db.users.create(user)),
a.procedure('example', () => fetch('https://api.com/example')),
// ...etc
]
})
Note, we could also use the request integration for type validated fetch requests and responses.
Server
actions
Actions are a @solidjs/router
paradigm for communicating with server, usually (but not only) with forms.
import { action, useAction } from '@solidjs/router'
import { usersAPI } from '@/api/users'
const createUser = action(async (user: User) => usersAPI.call('createUser', user))
export function MyComponent() {
const createUserAction = useAction(createUser)
return (
<button onClick={() => createUserAction({ name: 'New User' })}>
Create New User
</button>
)
}
or with a <form>
import { action, useAction } from '@solidjs/router'
import { usersAPI } from '@/api/users'
const createUser = action(async (user: FormData) => usersAPI.call('createUser', user))
export function MyComponent() {
return (
<form action={createUser} method="POST">
<label for="username">Username:</label>
<input type="text" name="username" />
<button type="submit">submit</build>
</form>
)
}
route loaders
Since solid is opinionated with it’s primitives, here’s an example using @solidjs/router
for a server-side load.
import { createAsync, cache } from '@solidjs/router'
import { For } from 'solid-js'
import { usersAPI } from '@/api/users'
const getAllUsers = cache(async () => {
'use server'
return usersAPI.call('getAllUsers')
}, 'getAllUsers')
export const route = {
load: () => getAllUsers()
}
export default function Page() {
const users = createAsync(() => getAllUsers())
return (
<For each={users()}>{user => <li>{user.name}</li>}</For>
)
}
Client
While it’s preferred to fetch what you can on server, there are times when you need to fetch data on client.
createResource
For client, we just call the resource signal
import { createResource } from 'solid-js'
import { usersAPI } from '@/api/users'
export default function Page({ id }: { id: string }) {
const [user] = createResource(id, (id: string) => usersAPI.call('getUserById', id))
return <div>{user().name}</div>
}
routes (cache + createAsync)
It’s the same as the server - route loaders examples, just remove the 'use server'
from the cache function.
@tanstack/solid-query
There’s an official integration for @tanstack/solid-query
as well, which is fairly popular in the solidjs ecosystem.
What’s exciting, there’s an official @hulla/api-query
integration. While you can read more about
the integration itself and learn how it works by following the link, here’s at least a minimal example with it.
import { api } from '@hulla/api'
import { query } from '@hulla/api-query'
const a = api()
export const usersAPI = a.router({
name: 'users',
routes: [
a.procedure('getUserById', (id: string) => db.users.get(id)),
a.procedure('createUser', (user: User) => db.users.create(user)),
a.procedure('example', () => fetch('https://api.com/example')),
// ...etc
],
adapters: { query }
})
and then later in your component / page ui route
import { createQuery } from '@tanstack/solid-query'
import { usersAPI } from '@/api/users'
export default function UsersPage() {
const { data } = createQuery(usersAPI.query.call('getAllUsers')) // 🚀 that's all!
// ...
}
Demo
Demo is coming up!