A user registration API allows a mobile application to send new user information to a server and save it in a MySQL database. In this lesson, we will create a PHP REST API for registering users using JSON, PDO, validation, prepared statements, and proper API responses.
User registration is the process of creating a new user account in an application.
Mobile App
↓
Registration Form
↓
PHP REST API
↓
Validation
↓
MySQL Database
↓
Registration Response
A typical registration request follows this flow:
For this example, we can use a users table with fields such as:
users
id
name
email
mobile
password
created_at
The exact table structure can be adjusted according to your project.
A registration API can use a POST endpoint.
POST /api/register.php
POST is appropriate because the API is creating a new user resource.
header("Content-Type: application/json");
This tells the client that the API response is returned in JSON format.
$pdo = new PDO(
"mysql:host=localhost;dbname=schooldb",
"root",
""
);
$pdo->setAttribute(
PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION
);
PDO provides a convenient and secure way to communicate with MySQL.
JSON data sent by a mobile application can be read using php://input.
$input = file_get_contents(
"php://input"
);
$data = json_decode(
$input,
true
);
The React Native application can send data such as:
{
"name": "Rahul Kumar",
"email": "rahul@example.com",
"mobile": "9876543210",
"password": "MyPassword123"
}
$input = file_get_contents(
"php://input"
);
$data = json_decode(
$input,
true
);
if (json_last_error() !== JSON_ERROR_NONE) {
http_response_code(400);
echo json_encode([
"success" => false,
"message" => "Invalid JSON data"
]);
exit;
}
Invalid JSON should be rejected before processing the registration.
$name = trim(
$data['name'] ?? ''
);
$email = trim(
$data['email'] ?? ''
);
$mobile = trim(
$data['mobile'] ?? ''
);
$password = $data['password'] ?? '';
Using the null coalescing operator helps prevent undefined array key warnings when a field is missing.
if (
$name === '' ||
$email === '' ||
$mobile === '' ||
$password === ''
) {
http_response_code(400);
echo json_encode([
"success" => false,
"message" => "All fields are required"
]);
exit;
}
PHP provides filter_var() for email validation.
if (!filter_var(
$email,
FILTER_VALIDATE_EMAIL
)) {
http_response_code(422);
echo json_encode([
"success" => false,
"message" => "Invalid email address"
]);
exit;
}
A simple validation can check whether the mobile number contains the expected number of digits.
if (!preg_match(
'/^[0-9]{10}$/',
$mobile
)) {
http_response_code(422);
echo json_encode([
"success" => false,
"message" => "Invalid mobile number"
]);
exit;
}
You can enforce a minimum password length before creating an account.
if (strlen($password) < 6) {
http_response_code(422);
echo json_encode([
"success" => false,
"message" =>
"Password must be at least 6 characters"
]);
exit;
}
For production applications, stronger password rules can be added.
Before inserting a user, check whether the email is already registered.
$stmt = $pdo->prepare(
"SELECT id
FROM users
WHERE email = ?"
);
$stmt->execute([$email]);
if ($stmt->fetch()) {
http_response_code(409);
echo json_encode([
"success" => false,
"message" => "Email already registered"
]);
exit;
}
An email is often used as a unique identifier for a user account. Allowing duplicate emails can create problems during login.
Registration Request
↓
Check Email
↓
Already Exists?
┌────┴────┐
Yes No
↓ ↓
409 Error Continue
↓
Create User
Never store a user's password directly in the database. PHP provides password_hash() for securely hashing passwords.
$hashedPassword = password_hash(
$password,
PASSWORD_DEFAULT
);
$stmt = $pdo->prepare(
"INSERT INTO users
(name, email, mobile, password)
VALUES (?, ?, ?, ?)"
);
$stmt->execute([
$name,
$email,
$mobile,
$hashedPassword
]);
Prepared statements should be used instead of directly inserting user input into SQL queries.
After a successful INSERT, PDO can return the new record ID.
$userId = $pdo->lastInsertId();
This ID can be included in the registration response if required.
http_response_code(201);
echo json_encode([
"success" => true,
"message" => "Registration successful",
"user_id" => $userId
]);
HTTP 201 is appropriate when a new user resource has been created.
A reusable error function keeps the registration API clean.
function sendError(
int $status,
string $message
) {
http_response_code($status);
echo json_encode([
"success" => false,
"message" => $message
]);
exit;
}
if ($name === '') {
sendError(
400,
"Name is required"
);
}
if (!filter_var(
$email,
FILTER_VALIDATE_EMAIL
)) {
sendError(
422,
"Invalid email address"
);
}
The same function can handle different registration errors.
try {
$stmt = $pdo->prepare(
"INSERT INTO users
(name, email, mobile, password)
VALUES (?, ?, ?, ?)"
);
$stmt->execute([
$name,
$email,
$mobile,
$hashedPassword
]);
} catch (PDOException $e) {
error_log(
$e->getMessage()
);
sendError(
500,
"Registration failed"
);
}
POST Request
↓
Read JSON
↓
Validate JSON
↓
Validate Fields
↓
Check Email
↓
Hash Password
↓
Insert User
↓
Return JSON Response
To test the registration API in Postman:
{
"name": "Rahul Kumar",
"email": "rahul@example.com",
"mobile": "9876543210",
"password": "MyPassword123"
}
React Native can send the registration data using fetch().
fetch("https://example.com/api/register.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "Rahul Kumar",
email: "rahul@example.com",
mobile: "9876543210",
password: "MyPassword123"
})
})
.then(response => response.json())
.then(data => {
console.log(data);
});
fetch(url, options)
.then(async response => {
const data =
await response.json();
if (!response.ok) {
throw new Error(
data.message
);
}
return data;
})
.then(data => {
console.log(
"Registration successful"
);
})
.catch(error => {
console.log(
error.message
);
});
<?php
header("Content-Type: application/json");
function sendError(
int $status,
string $message
) {
http_response_code($status);
echo json_encode([
"success" => false,
"message" => $message
]);
exit;
}
try {
$pdo = new PDO(
"mysql:host=localhost;dbname=schooldb",
"root",
""
);
$pdo->setAttribute(
PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION
);
$input = file_get_contents(
"php://input"
);
$data = json_decode(
$input,
true
);
if (json_last_error() !== JSON_ERROR_NONE) {
sendError(400, "Invalid JSON data");
}
$name = trim(
$data['name'] ?? ''
);
$email = trim(
$data['email'] ?? ''
);
$mobile = trim(
$data['mobile'] ?? ''
);
$password =
$data['password'] ?? '';
if (
$name === '' ||
$email === '' ||
$mobile === '' ||
$password === ''
) {
sendError(
400,
"All fields are required"
);
}
if (!filter_var(
$email,
FILTER_VALIDATE_EMAIL
)) {
sendError(
422,
"Invalid email address"
);
}
if (!preg_match(
'/^[0-9]{10}$/',
$mobile
)) {
sendError(
422,
"Invalid mobile number"
);
}
if (strlen($password) < 6) {
sendError(
422,
"Password must be at least 6 characters"
);
}
$stmt = $pdo->prepare(
"SELECT id FROM users WHERE email = ?"
);
$stmt->execute([$email]);
if ($stmt->fetch()) {
sendError(
409,
"Email already registered"
);
}
$hashedPassword = password_hash(
$password,
PASSWORD_DEFAULT
);
$stmt = $pdo->prepare(
"INSERT INTO users
(name, email, mobile, password)
VALUES (?, ?, ?, ?)"
);
$stmt->execute([
$name,
$email,
$mobile,
$hashedPassword
]);
$userId = $pdo->lastInsertId();
http_response_code(201);
echo json_encode([
"success" => true,
"message" => "Registration successful",
"user_id" => $userId
]);
} catch (PDOException $e) {
error_log(
$e->getMessage()
);
sendError(
500,
"Registration failed"
);
}
?>
A registration API connects the mobile registration form with the backend database. The client sends JSON using POST, PHP validates the information, checks for duplicate users, securely hashes the password, stores the user with a prepared statement, and returns a JSON response.
React Native
↓
POST JSON
↓
PHP Registration API
↓
Validate Data
↓
Check Duplicate
↓
Hash Password
↓
PDO + MySQL
↓
201 Created
↓
JSON Response
Question: Which PHP function should be used to securely hash a user's password before storing it in the database?