📂 Category
Category exposes public category reads and administrator-only creation, editing, status, and deletion operations through categoryService.
Start here
Mount the service below /api. It needs MongoDB categories and identities collections, authSecrets, and configured identity type IDs for protected mutations. defService installs JSON parsing on the returned router; register cookie-parser before the service only when authMode is 'cookie'.
The exported categoryService is a Service<CategoryServiceDataStore, CategoryServiceConfiguration> that returns an Express router from (dataStores, configuration, drivers?).
import express from 'express';
import { services } from '@nodeblocks/backend-sdk';
const app = express();
app.use('/api', services.categoryService(
{ categories, identities },
{
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET!,
authSignSecret: process.env.AUTH_SIGN_SECRET!,
},
authMode: 'bearer',
identity: { typeIds: { admin: 'admin-type-id', guest: 'guest-type-id', regular: 'regular-type-id' } },
},
));
| Configuration | Default / source behavior | Effect |
|---|---|---|
authSecrets.authEncSecret / authSecrets.authSignSecret | Required by the service configuration; passed to authentication utilities | Required runtime authentication configuration. |
identity.typeIds.admin | Required by protected-route authorization; read by checkIdentityType(['admin']) | Selects the identity type allowed to mutate categories. |
authMode | Omitted or 'bearer' selects getBearerTokenInfo; 'cookie' selects getCookieTokenInfo | Changes the protected-route token transport. |
Public routes do not compose authentication validators. Protected routes run isAuthenticated() and then checkIdentityType(['admin']); cookie mode therefore requires cookie middleware in the host application.
The service executor returns ordinary handler values through res.json(result), which supplies the 200 status documented for Category read/create/update routes. A terminator that returns { statusCode: 204 } instead uses res.status(204).json(undefined). Category defines no domain block exports; its routes use Category handlers plus shared entity and pagination utilities.
Common tasks
| Task | Start with | Contract |
|---|---|---|
| Read one category or list categories | Public routes | Routes and list schema |
| Create or edit a category | Administrator access token or cookie | Create, update |
| Change status or delete | Administrator access token or cookie | Status and delete routes |
| Compose selected endpoints | Feature composers | Features |
Bearer HTTP workflow
Declare the shell values before using a protected endpoint:
export ADMIN_ACCESS_TOKEN='replace-with-an-admin-access-token'
export CATEGORY_ID='replace-with-a-category-id'
curl 'http://localhost:8080/api/categories?name=Electronics&page=1&limit=20'
curl -X POST 'http://localhost:8080/api/categories' \
-H "authorization: Bearer $ADMIN_ACCESS_TOKEN" \
-H 'content-type: application/json' \
-d '{"name":"Electronics","description":"Devices and accessories","status":"active"}'
curl -X POST "http://localhost:8080/api/categories/$CATEGORY_ID/disable" \
-H "authorization: Bearer $ADMIN_ACCESS_TOKEN"
The list returns 200 with { data, metadata: { pagination } }; omitted pagination values default to page 1 and limit 10. Creation returns 200 with the normalized category. Disabling succeeds with an empty 204; a missing category is rejected by doesCategoryExist with 404. See the route matrix and request schemas.
Cookie HTTP workflow
With authMode: 'cookie', register cookie-parser before the Category mount, obtain the access cookie through the Authentication cookie workflow, then send the stored cookie rather than an Authorization header:
export CATEGORY_ID='replace-with-a-category-id'
curl -X PATCH "http://localhost:8080/api/categories/$CATEGORY_ID" \
-b cookies.txt \
-H 'content-type: application/json' \
-d '{"description":"Updated category description"}'
This request requires the same administrator identity as the Bearer workflow and returns the normalized category on success.
Custom feature composition
This fragment mounts only create, list, and status operations. Its host must provide categories, identities, authentication secrets, and identity type IDs. defService installs JSON parsing; cookie mode additionally needs cookie-parser.
import { partial } from 'ramda';
import { features, primitives, utils } from '@nodeblocks/backend-sdk';
const composeCategoryRoutes = primitives.compose(
features.createCategoryFeature,
features.findCategoriesFeatures,
features.editCategoryStatusFeatures,
);
const configuration = {
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET!,
authSignSecret: process.env.AUTH_SIGN_SECRET!,
},
identity: {
typeIds: {
admin: 'admin-type-id',
guest: 'guest-type-id',
regular: 'regular-type-id',
},
},
};
const categoryRouter = primitives.defService(partial(composeCategoryRoutes, [{
authenticate: utils.getBearerTokenInfo,
configuration,
dataStores: { categories, identities },
}]));
app.use('/api', categoryRouter);
For cookie transport, substitute utils.getCookieTokenInfo and register cookie-parser in the host application.
Reference map
| Page | Purpose |
|---|---|
| Features | Schema and route composition. |
| Handlers | Pipeline operations and response terminators. |
| Routes | Exact endpoint, access, and response contracts. |
| Schemas | Request and reusable object contracts. |
| Validators | Category-existence and shared access guards. |
There is no Category blocks page because the SDK exports no Category-specific block layer.
Related modules
See Category service for service-level use, Authentication for access-token and cookie setup, validator component for route validation, and error handling for shared error responses.