01
Keep data request-local
Use the server DataContext and data helper to share a single in-flight load within one request. This avoids duplicate work without turning user data into a mutable global.
- Validate loaded data before rendering it.
- Keep database clients and private services server-only.
- Use a safe key for request-local data deduplication.
02
Forms begin as HTML
Use Form and SubmitButton for the standard progressive path. The action and method remain the fallback while the Nexis forms runtime provides pending state and typed responses.
- Use POST for mutations.
- Provide labels and browser validation as usability, not security.
- Show result status through an aria-live region when enhanced.
03
Actions own mutation policy
The framework action pipeline validates input, can authorize, and handles the endpoint envelope. Application code remains responsible for resource ownership, audit records, and durable stores.
- Validate types, length, range, and allowed values server-side.
- Use Origin checks and CSRF policy.
- Use durable idempotency for retriable non-repeatable mutations.
import { action } from '@mohammedaydan/actions'
import { Form, SubmitButton } from '@mohammedaydan/core'
const saveProfile = action({
endpoint: '/__nexis/actions/profile/save',
validate: (input) => parseProfileInput(input),
authorize: async (context, input) => requireProfileOwner(context.request, input.userId),
handle: async (_context, input) => updateProfile(input),
})
export function ProfileForm({ csrfToken }: { readonly csrfToken: string }) {
return <Form action={saveProfile} csrfToken={csrfToken}>
<label htmlFor="name">Name</label>
<input id="name" name="name" required />
<SubmitButton loadingText="Saving…">Save profile</SubmitButton>
</Form>
}PRACTICE LAB
Prove the behavior.
Write a failing test for invalid data and another for a rejected owner check before implementing a successful update.