In this lesson, we will create the Delete Student API for our Student Management mobile application.
The React Native application will send a DELETE request using Axios. The PHP REST API will verify the JWT, validate the student ID, check whether the student exists, and delete the student record from MySQL using PDO.
React Native Student List
↓
Delete Button
↓
Confirmation
↓
Axios DELETE
↓
students.php?id=5
↓
JWT Verification
↓
Validate Student ID
↓
Check Student
↓
PDO DELETE
↓
MySQL
↓
JSON Response
The HTTP DELETE method is used when we want to remove an existing resource from the server.
DELETE /api/students.php?id=5
Here, 5 identifies the student that should be deleted.
Deleting a student is a sensitive operation. Therefore, the API should not allow anonymous users to delete records.
Authorization:
Bearer YOUR_JWT_TOKEN
The server should verify the JWT before executing the DELETE query.
header(
"Content-Type: application/json"
);
The API uses JSON for its response.
require_once '../config/database.php';
The existing PDO database connection can be reused by the delete endpoint.
if ($_SERVER['REQUEST_METHOD'] !== 'DELETE') {
http_response_code(405);
echo json_encode([
"success" => false,
"message" => "Method not allowed"
]);
exit;
}
This prevents GET, POST, or other methods from accidentally reaching the delete logic.
$headers = getallheaders();
$authorization =
$headers['Authorization']
?? '';
The Authorization header contains the Bearer JWT sent by the mobile application.
if (
!preg_match(
'/Bearer\s(\S+)/',
$authorization,
$matches
)
) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" =>
"Authentication required"
]);
exit;
}
$token = $matches[1];
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
try {
$decoded = JWT::decode(
$token,
new Key(
$secretKey,
'HS256'
)
);
} catch (Exception $e) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" =>
"Invalid or expired token"
]);
exit;
}
The server should never trust a token simply because it exists. The signature and expiration must be verified.
$id = filter_input(
INPUT_GET,
'id',
FILTER_VALIDATE_INT
);
The student ID is received from the query parameter.
DELETE /api/students.php?id=5
if (!$id || $id <= 0) {
http_response_code(400);
echo json_encode([
"success" => false,
"message" =>
"Valid student ID is required"
]);
exit;
}
Always validate the ID before using it in the database query.
$stmt = $pdo->prepare(
"SELECT id
FROM students
WHERE id = ?"
);
$stmt->execute([$id]);
$student = $stmt->fetch(
PDO::FETCH_ASSOC
);
if (!$student) {
http_response_code(404);
echo json_encode([
"success" => false,
"message" =>
"Student not found"
]);
exit;
}
Checking existence lets the API return a clear 404 response instead of reporting a successful deletion for a record that does not exist.
DELETE FROM students
WHERE id = ?
The placeholder is replaced safely using a prepared statement.
$stmt = $pdo->prepare(
"DELETE FROM students
WHERE id = ?"
);
$stmt->execute([$id]);
Prepared statements help prevent SQL injection.
$deleted =
$stmt->rowCount();
rowCount() can be used to determine how many rows were
affected by the DELETE operation.
http_response_code(200);
echo json_encode([
"success" => true,
"message" =>
"Student deleted successfully"
]);
The mobile application can use this response to remove the student from the displayed list.
<?php
header(
"Content-Type: application/json"
);
require_once '../config/database.php';
require_once __DIR__ .
'/vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$secretKey =
'CHANGE_THIS_TO_A_LONG_RANDOM_SECRET';
if ($_SERVER['REQUEST_METHOD'] !== 'DELETE') {
http_response_code(405);
echo json_encode([
"success" => false,
"message" => "Method not allowed"
]);
exit;
}
$headers = getallheaders();
$authorization =
$headers['Authorization']
?? '';
if (
!preg_match(
'/Bearer\s(\S+)/',
$authorization,
$matches
)
) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" =>
"Authentication required"
]);
exit;
}
$token = $matches[1];
try {
JWT::decode(
$token,
new Key(
$secretKey,
'HS256'
)
);
$id = filter_input(
INPUT_GET,
'id',
FILTER_VALIDATE_INT
);
if (!$id || $id <= 0) {
http_response_code(400);
echo json_encode([
"success" => false,
"message" =>
"Valid student ID is required"
]);
exit;
}
$stmt = $pdo->prepare(
"SELECT id
FROM students
WHERE id = ?"
);
$stmt->execute([$id]);
if (!$stmt->fetch()) {
http_response_code(404);
echo json_encode([
"success" => false,
"message" =>
"Student not found"
]);
exit;
}
$stmt = $pdo->prepare(
"DELETE FROM students
WHERE id = ?"
);
$stmt->execute([$id]);
http_response_code(200);
echo json_encode([
"success" => true,
"message" =>
"Student deleted successfully"
]);
} catch (Exception $e) {
error_log($e->getMessage());
http_response_code(401);
echo json_encode([
"success" => false,
"message" =>
"Invalid or expired token"
]);
}
React Native can use Axios to send the DELETE request.
const response =
await api.delete(
`/students.php?id=${studentId}`
);
The api Axios instance can automatically add the JWT
Authorization header through the interceptor created earlier.
A confirmation dialog is recommended before permanently deleting a student.
Alert.alert(
"Delete Student",
"Are you sure you want to delete this student?",
[
{
text: "Cancel",
style: "cancel"
},
{
text: "Delete",
onPress: () =>
deleteStudent(studentId)
}
]
);
const deleteStudent =
async (studentId: number) => {
try {
const response =
await api.delete(
`/students.php?id=${studentId}`
);
if (response.data.success) {
Alert.alert(
"Success",
response.data.message
);
}
} catch (error) {
Alert.alert(
"Error",
"Unable to delete student"
);
}
};
interface DeleteStudentResponse {
success: boolean;
message: string;
}
This interface describes the JSON response returned by the PHP API.
const response =
await api.delete<DeleteStudentResponse>(
`/students.php?id=${studentId}`
);
TypeScript now knows the expected structure of
response.data.
After a successful delete, the application can remove the student from the local state.
setStudents(
students.filter(
student =>
student.id !== studentId
)
);
This immediately updates the displayed list without requiring the user to restart the application.
try {
await api.delete(
`/students.php?id=${studentId}`
);
} catch (error) {
if (
axios.isAxiosError(error) &&
error.response
) {
const status =
error.response.status;
if (status === 401) {
// Login again
}
else if (status === 404) {
// Student not found
}
else if (status === 403) {
// Permission denied
}
else {
// Other API error
}
}
}
| Status | Meaning |
|---|---|
| 200 | Student deleted successfully |
| 400 | Invalid student ID |
| 401 | Authentication required or token invalid |
| 403 | User does not have permission |
| 404 | Student not found |
| 405 | HTTP method not allowed |
| 500 | Server/database error |
Method: DELETE
URL:
https://example.com/api/students.php?id=5
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
Send the request and check the JSON response.
{
"success": true,
"message": "Student deleted successfully"
}
A student may have related records in other tables such as payments, attendance, assignments, or results.
Before deleting a student permanently, the database design should decide whether related records should also be deleted, preserved, or disconnected.
students
|
+---- payments
|
+---- attendance
|
+---- assignments
|
+---- results
is_deleted field when historical records must be preserved.
Student List
↓
Delete Button
↓
Confirmation Alert
↓
Axios DELETE
↓
JWT Authorization
↓
PHP REST API
↓
Verify JWT
↓
Validate ID
↓
Check Student
↓
PDO DELETE
↓
MySQL
↓
JSON Response
↓
Update React Native State
↓
Student Removed from List
The Delete Student API completes the DELETE operation of our student management backend.
?id=.rowCount() can inspect affected rows.Question: Which HTTP method is used to delete a student from the REST API?