Resource Type Naming: singular or plural? What to choose? Why is that?
- ⮐ Cookbook
Every resource in WarpDrive has a type: the type string that identifies it in API responses, in its ResourceSchema, in the relationship fields that point to it and in the requests that fetch it. WarpDrive has no rule about what that string looks like. It can be singular or plural, dasherized or snake_case. It only has to be the same string everywhere.
Why older apps use singular, dasherized types
The legacy serializers in @warp-drive/legacy singularize and dasherize every type they receive, so apps that use them end up with types like user-setting no matter what the API sends.
Without those serializers, WarpDrive uses the type your API sends as-is, and normalizing it is up to you.
So what to choose?
Whatever your API already sends. You can choose singular or plural names, but it is usually best to let the backend decide and treat the type as part of your app's API contract, rather than renaming every type on the frontend. Whichever you choose, stick with it. Be Consistent!
What does consistency look like?
Let's say your convention is singular dasherized, e.g. user-setting
The API responds with
"type": "user-setting", or a handler normalizes the type to that.The ResourceSchema's
typeand every relationship field'stypethat points to it use the same string:tsimport { withDefaults } from '@warp-drive/legacy/model/migration-support'; export const UserSettingSchema = withDefaults({ type: 'user-setting', fields: [{ kind: 'attribute', name: 'value' }], }); export const UserSchema = withDefaults({ type: 'user', fields: [ { kind: 'hasMany', name: 'userSettings', type: 'user-setting', options: { async: false, inverse: null }, }, ], }); // wherever you configure the store store.schema.registerResources([UserSchema, UserSettingSchema]);Requests made with a request builder use it too:
tsimport { findRecord } from '@warp-drive/utilities/json-api'; const { content } = await store.request(findRecord('user-setting', '1'));
But what about plural and snake case?
The same places use user_settings instead:
The API responds with
"type": "user_settings".The schema and the relationship field use it:
tsexport const UserSettingSchema = withDefaults({ type: 'user_settings', fields: [{ kind: 'attribute', name: 'value' }], }); // in UserSchema's fields { kind: 'hasMany', name: 'userSettings', type: 'user_settings', options: { async: false, inverse: null }, }So do requests:
tsconst { content } = await store.request(findRecord('user_settings', '1'));
The example schemas use LegacyMode, which despite its name is the recommended mode today. The resource type rules are the same in PolarisMode and for apps still defining Model classes.
💡 The type and the URL are separate
The findRecord builder from @warp-drive/utilities/json-api builds the URL path by pluralizing the type you pass. If your endpoint uses a different path, keep the type as it is and pass the resourcePath option to findRecord instead.
But what about the JSON:API spec?
The JSON:API spec is agnostic about how type is named. Here is the quote from the spec:
Note: This spec is agnostic about inflection rules, so the value of
typecan be either plural or singular. However, the same value should be used consistently throughout an implementation.
You can read more about it in the JSON:API spec.
- ⮐ Cookbook