This is surprisingly difficult given all the good press decoupled Drupal has gotten over the past few years-- user registration in Core has bugs that make it impossible to use without patching.
Building on Alireza Tabatabaeian's answer, this answer is specifically for
- Using the Email Registration module.
- Requiring users to verify their email addresses.
- Doing it in React/TypeScript (code example at the end)
Detailed steps
First, enable Rest UI.
Navigate to /admin/config/services/rest
.
Enable User registration
.
Configure as follows:
- Granularity:
Resource
- Methods:
POST
- Accepted request formats:
json
- Authentication providers:
cookie
Next, at /admin/people/permissions#module-rest
, give the anonymous user Access POST on User Registration resource
permission.
Testing on Postman
You should now be able to test on Postman.
Here's how to format the request.
- Select
POST
.
- For the url, use
http://www.example.com/user/register?_format=json
.
- For the headers:
- Content-Type: application/json
- Accept: application/json
- X-CSRF-TOKEN: (use value from
GET
to http://www.example.com/session/token
For the request body:
raw format
And then use this value:
{
"name":{"value":"test"},
"mail":{"value":"[email protected]"}
}
You will need to add pass
as well if you are not requiring email verification.
If you are requiring email verification, there is a Core bug that will block all users registered via REST and prevent email validation. You will need the patch from this issue.
React TypeScript Ionic code example
UserRegistrationForm.tsx
import * as React from 'react';
import { useForm } from 'react-hook-form';
import {
IonButton, IonItem, IonLabel, IonInput,
} from '@ionic/react';
import { baseUrl, restHeaders } from '../utils/globals';
import handleErrors from '../utils/fetchHandleErrors';
import { fetchWithCSRFToken } from '../utils/fetch';
import ErrorSummary from '../utils/ErrorSummary';
interface InterfaceRegistrationFormInput {
email: string;
}
const UserRegistrationForm: React.VFC = () => {
const {
register, handleSubmit, errors, setError,
} = useForm<InterfaceRegistrationFormInput>();
const onSubmit = (formData: any) => {
const myRegData = {
name: {
value: Date.now(),
},
mail: {
value: formData.mail,
},
};
fetchWithCSRFToken(`${baseUrl}/user/register?_format=json`, {
method: 'POST',
headers: restHeaders,
body: JSON.stringify(myRegData),
})
.then(handleErrors)
.then((response) => {
console.log('response', response);
})
.catch((error: any) => {
if (error.message === 'Unprocessable Entity') {
setError('email', {
type: 'manual',
message: 'You have already registered.',
});
} else {
setError('email', {
type: 'manual',
message: 'Unknown error.',
});
}
});
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<IonItem>
<ErrorSummary errors={errors} />
<IonLabel position="stacked">
Email address
</IonLabel>
<IonInput
name="mail"
type="email"
ref={register({ required: true }) as any}
/>
</IonItem>
<IonButton type="submit">Register</IonButton>
</form>
);
};
export default UserRegistrationForm;
globals.tsx
export const restHeaders: HeadersInit = new Headers({
'Content-Type': 'application/json',
Accept: 'application/json',
});
fetchHandleErrors.tsx
// Throw exceptions instead of fetch default behavior.
// https://www.tjvantoll.com/2015/09/13/fetch-and-errors/
export default function handleErrors(response: Response): Response {
if (!response.ok) {
throw new Error(response.statusText);
}
return response;
}
fetch.tsx
export const fetchWithCSRFToken = (fetchUrl: string, fetchOptions: any) => {
if (!fetchOptions.headers.get('X-CSRF-Token')) {
const csrfUrl = `${baseUrl}/session/token`;
return fetch(csrfUrl)
.then((response) => response.text())
.then((csrfToken) => {
// console.log('csrfToken', csrfToken);
fetchOptions.headers.append('X-CSRF-Token', csrfToken);
return fetch(fetchUrl, fetchOptions);
});
}
return fetch(fetchUrl, fetchOptions);
};
ErrorSummary.tsx
import React from 'react';
import { ErrorMessage } from '@hookform/error-message';
import { FieldErrors } from 'react-hook-form';
type ErrorSummaryProps<T> = {
errors: FieldErrors<T>;
};
// https://www.carlrippon.com/react-hook-form-validation-errors/
function ErrorSummary<T>({ errors }: ErrorSummaryProps<T>) {
if (Object.keys(errors).length === 1) {
return null;
}
return (
<div className="error-summary">
{Object.keys(errors).map((fieldName) => (
<ErrorMessage errors={errors} name={fieldName as any} as="div" key={fieldName} />
))}
</div>
);
}
export default ErrorSummary;
--data '{"name":"admin", "pass":"admin"}'
POST
onexample.com/user/register
as suggested in the documentation returns the registration page itself. So there's no error to see what is going wrong.curl \ --user uname:password \ --header 'Accept: application/json' \ --header 'Content-type: application/json' \ --request POST http://drupal8.dev/user/register \ --data-binary @post_data.json
where post_data.json file has your user data.