🎁 Upgrade to Feathers-Pinia 2.0 🎁
Feathers-Pinia 2.0 is almost ready for final release. Read the new documentation.Service Stores
Setup
We learned the basics of how to create service stores on the setup page. Let's cover the topic in more detail.
Using defineStore 
Here's a look at the DefineStoreOptions interface. By the way, there's lots of room for TypeScript improvements in the codebase. Pull Requests are very much encouraged!
import { Application as FeathersClient } from '@feathersjs/feathers'
interface DefineStoreOptions {
  ssr?: boolean
  servicePath: string
  Model?: any
  idField?: 'id' | '_id' | string
  tempIdField?: '__tempId' | string
  id?: string
  clientAlias?: 'api' | string
  clients?: { [alias: string]: FeathersClient }
  handleEvents?: HandleEvents
  enableEvents?: boolean
  debounceEventsTime?: number
  debounceEventsGuarantee?: boolean
  whitelist?: string[]
  paramsForServer?: string[]
  state?: () => { [k: string]: any }
  getters?: { [k: string]: (state: any) => any }
  actions?: { [k: string]: Function }
}
interface HandleEvents {
  created?: Function
  patched?: Function
  updated?: Function
  removed?: Function
}
Here are a few more details about each option:
ssr {Boolean}indicates if Feathers-Pinia is loading in an SSR environment. Paginated queries made during SSR will be marked withssr: true.servicePath {String}is the same as the Feathers service path. requiredModel {ModelClass}is the class to use for each instance. If you don't provide one, a generic class extendingBaseModelwill be created and used. For any record-level logic, you'll need t create a custom class extending BaseModel. See Model ClassesidField {String}is the attribute on the record that will serve as the unique identifier or "primary key" in the database. See Model Classes for a recipe that might work for compound keys (multiple fields).tempIdField {String}is the attribute on the record that will serve as the unique identifier for items that are temporarily created in the store but not send to the server yetid {String}is the identifier of the Pinia store.clientAlias {String}is the name of the FeathersClient instance to use for this service. See State. It must match a value in theclientsoption. Defaults toapiclients {Object}is an object whose keys areclientAliasstrings with their correspondingFeathersClientvalues. The defaultapikey must be provided. Additional keys can represent clients to other API servers.enableEvents {Boolean}enables and disables the built-in realtime event handlers. Defaults totrue.handleEvents {Object}is an object that lets you customize how realtime events are handled. Each key is a name of a realtime event handler function:created,patched,updated, orremoved. By default, each handler returns the value ofenableEvents, which is why settingenableEventsto false will disable all handlers. You can provide your own handler to customize and override individual events.debounceEventsTime {Number}determines how long to wait until flushing a batch of events. Defaults to20. If no events have been received in a 20 millisecond period, all gathered events will be processed.debounceEventsGuarantee {Boolean}forces accumulated events to flush everydebounceEventsTimeinterval. Off by default.whitelistis an array of keys to allow in thefindInStoregetter'sparams.queryobject.paramsForServeris an array of keys to allow in the params object for thefindactions'sparams.queryobject but to omit on thefindInStoregetter'sparams.queryobject.stateis a function that returns an object of custom state to customize the store.gettersis an object of custom getters to customize the store.actionsis an object of custom actions to customize the store.
State
Here's the interface for the Service State
export interface ServiceState<M extends Model = Model> {
  clientAlias: string
  servicePath: string
  pagination: {
    [k: string]: any
  }
  idField: string
  tempIdField: string
  itemsById: {
    [k: string]: M
    [k: number]: M
  }
  tempsById: {
    [k: string]: M
    [k: number]: M
  }
  clonesById: {
    [k: string]: M
    [k: number]: M
  }
  pendingById: {
    [k: string]: PendingById | ModelPendingState
    [k: number]: PendingById
  }
  eventLocksById: {
    created: { [k: string]: M; [k: number]: M }
    patched: { [k: string]: M; [k: number]: M }
    updated: { [k: string]: M; [k: number]: M }
    removed: { [k: string]: M; [k: number]: M }
  }
  whitelist?: string[]
}
Let's go over each part of the state in more detail:
clientAliasis the same as theclientAliasoption that was provided during setup. See theservicegetter.servicePathis the same as theservicePathoption that was provided during setup. See theservicegetter.paginationkeeps track of the latest pagination data for each paginated request to the server. You generally won't manually modify this.idFieldis the same as theidFieldoption that was provided during setup. It specifies which field is the "primary key" identifier in the database.tempIdFieldis the same as thetempIdFieldoption that was provided during setup. It specifies which field is the temporary identifier.itemsByIdgenerally contains records retrieved from the API server.tempsByIdholds records that don't have anidFieldassigned from the API server. They only exist on the client.clonesByIdall clones, keyed by id. See Model Instances.pendingByIdkeeps track of individual records that have pending requests. This powers theisSavePendingand similar getters on each record. See Model Instances.eventLocksByIdhelps prevent receiving normal, duplicate responses from the API server during CRUD actions. Instead of processing both the CRUD response AND the realtime event data, it only handles one of them.whitelistis an array of key names that are whitelisted in thefindInStoregetter params.
Getter Attributes
The following getters are available in every service store. Since they're getters, they are all reactive (meaning the template will update automatically as their values change). In the next section you'll find the getters that accepts arguments to query data from the store.
service 
Returns the FeathersClient service instance. This value is dynamic based on two values in the State.
- Change 
clientAliasto have the store use a different configured api server. - Change 
servicePathto have the store use a different service on the same api server. 
Model 
Gives access to the Model class provided during setup.
IDs & Lists
These getters return arrays of ids or instances currently in state.
itemIdsall keys fromitemsById.itemsall values fromitemsById.tempIdsall keys fromtempsById.tempsall values fromtempsById.cloneIdsall keys fromclonesById.clonesall values fromclonesById.
Pending Status
These getters return boolean pending status for this service store.
isCreatePendingwill be truthy when there's acreaterequest pending for this service.isPatchPendingwill be truthy when there's apatchrequest pending for this service.isUpdatePendingwill be truthy when there's aupdaterequest pending for this service.isRemovePendingwill be truthy when there's aremoverequest pending for this service.
Query Getters
These special getters accept arguments that allow you to query data from the store. Their return values are still reactive.
findInStore(params) 
Performs reactive queries against the data in itemsById. To also include data from tempsById, set params.temps to true.
Tip: use
findInStoreand enjoy Automatic Instance Hydration
countInStore(params) 
returns the total returned from findInStore, without returning the data.
getFromStore(id, params) 
Works similar to .get requests in a Feathers service object. It only returns records currently populated in the store.
Tip: use
getFromStoreand enjoy Automatic Instance Hydration
Actions
addToStore(data) 
Adds the data as a Model instance / multiple instances to the store.
removeFromStore(data) 
Removes the matching record(s) from the store.
find(params) 
Uses the Feathers Client to retrieve records from the API server. On an SSR server, find data will be marked as ssr: true, which allows extra queries to be skipped on the client.
<script setup>
import { useTodos } from '../store/todos'
const todoStore = useTodos()
todoStore.find({ query: {} }).then(/* ... */)
</script>
count(params) 
Like find, but returns the number of records that match the query. It does not return the actual records.
get(id, params) 
Uses the Feathers Client to retrieve a single record from the API server.
<script setup>
import { useTodos } from '../store/todos'
const todoStore = useTodos()
todoStore.get(1).then(/* ... */)
</script>
update(id, data, params) 
Uses the Feathers Client to send an update request to the API server.
patch(id, data, params) 
Uses the Feathers Client to send an patch request to the API server.
remove(id, params) 
Uses the Feathers Client to send a remove request to the API server.
afterFind(response) 
The afterFind method is a store-level callback that gets called with the response data once the response data has been added to the store. It's useful if you need to access additional keys on the reponse object.
export const useUsers = defineStore({
  servicePath,
  Model: User,
  actions: {
    afterFind (response: any) {
      // do extra processing on the response
    },
  },
})
See an example on the Common Patterns page.
Custom Properties
You can customize a store using the state, getters and actions options. It's possible to overwrite the built-in properties.
Server Side Rendering (SSR)
Automatic Instance Hydration
Normally, during SSR, after the rendered page has been delivered to the client, the browser takes any inline JSON payload and pushes it into the store. This is called hydration. A common problem with hydration is that it doesn't know about Feathers-Pinia Model classes, or that records should be instances. You recognize the problem when the browser throws an error stating something like:
Error: object has no method named `.save()`
That's because plain objects don't actually have a save() method. Only once a plain object has been turned back into a Model instance does it have a save() method. So we need to make sure that data is fully hydrated into an actual instance before using its methods.
Instead of automatically hydrating every instance in the store, Feathers-Pinia uses a more performant rule: Only hydrate the instances actually in use. It achieves this through the Query Getters. Any plain record returned by store.findInStore or store.getFromStore will automagically be turned into a fully hydrated model instance.