When a React Native application sends login information to a REST API, the server returns a response. TypeScript interfaces help us define the exact structure of this login response.
A login response is the data returned by the server after the user submits login credentials.
A typical flow is:
React Native
↓
Email + Password
↓
PHP Login API
↓
Verify User
↓
Login Response
↓
React Native
{
"success": true,
"message": "Login successful",
"token": "eyJhbGciOiJIUzI1NiJ9...",
"user": {
"id": 101,
"name": "Rahul Kumar",
"email": "rahul@example.com"
}
}
Without TypeScript, we may not know exactly which properties are available in the response.
An interface gives the response a clear structure.
interface LoginResponse {
success: boolean;
message: string;
token: string;
}
interface LoginResponse {
success: boolean;
message: string;
token: string;
}
Here, success is a boolean, while
message and token are strings.
interface User {
id: number;
name: string;
email: string;
}
The user object can then be included inside the login response.
interface User {
id: number;
name: string;
email: string;
}
interface LoginResponse {
success: boolean;
message: string;
token: string;
user: User;
}
const response =
await axios.post<LoginResponse>(
"/login",
{
email: "rahul@example.com",
password: "123456"
}
);
The generic type <LoginResponse> tells TypeScript
what structure to expect from the Axios response.
const token = response.data.token;
console.log(token);
Because the response is typed, TypeScript knows that
token exists as a string.
const userName = response.data.user.name;
const email = response.data.user.email;
console.log(userName);
console.log(email);
We can also create a separate interface for the data sent to the server.
interface LoginRequest {
email: string;
password: string;
}
This separates request data from response data.
const login = async (
data: LoginRequest
): Promise<LoginResponse> => {
const response =
await axios.post<LoginResponse>(
"/login",
data
);
return response.data;
};
Many applications return the user's role after successful login.
interface User {
id: number;
name: string;
email: string;
role: string;
}
The role can later be used by the application for navigation and display.
Instead of allowing any string, TypeScript can restrict the possible roles.
interface User {
id: number;
name: string;
email: string;
role: "admin" | "teacher" | "student";
}
This provides better type safety.
interface LoginResponse {
success: boolean;
message: string;
token: string;
user: {
id: number;
name: string;
email: string;
role: "admin" | "teacher" | "student";
};
}
Sometimes an API may not return user information when login fails. TypeScript can represent optional properties.
interface LoginResponse {
success: boolean;
message: string;
token?: string;
user?: User;
}
The question mark means the property may be absent.
{
"success": true,
"message": "Login successful",
"token": "abc123",
"user": {
"id": 10,
"name": "Amit",
"email": "amit@example.com",
"role": "student"
}
}
{
"success": false,
"message": "Invalid email or password"
}
A failed response may not contain a token or user object.
const response =
await login(data);
if (response.success) {
console.log(response.token);
console.log(response.user.name);
}
interface AuthState {
token: string | null;
user: User | null;
isAuthenticated: boolean;
}
This interface can be used with React Native state or an authentication context.
setAuth({
token: response.token,
user: response.user,
isAuthenticated: true
});
After successful login, the application can update the authentication state.
When JWT authentication is used, the token returned by the login API can be sent with future protected requests.
Authorization: Bearer <token>
The server verifies the JWT before returning protected information.
interface ProfileResponse {
success: boolean;
user: User;
}
const response =
await axios.get<ProfileResponse>(
"/profile",
{
headers: {
Authorization:
`Bearer ${token}`
}
}
);
console.log(response.data.user.name);
interface LoginErrorResponse {
success: false;
message: string;
code?: string;
}
A typed error structure makes authentication error handling easier.
{
"success": false,
"message": "Invalid credentials",
"code": "INVALID_CREDENTIALS"
}
Some applications return permissions along with the authenticated user.
interface User {
id: number;
name: string;
email: string;
role: "admin" | "teacher" | "student";
permissions: string[];
}
The server should remain responsible for enforcing these permissions.
A reusable generic interface can represent different API responses.
interface ApiResponse<T> {
success: boolean;
message: string;
data: T;
}
A login response can then be represented using
ApiResponse.
interface LoginData {
token: string;
user: User;
}
type LoginResponse =
ApiResponse<LoginData>;
This avoids repeating the same response structure across multiple APIs.
interface User {
id: number;
name: string;
email: string;
role: "admin" | "teacher" | "student";
}
interface LoginRequest {
email: string;
password: string;
}
interface LoginData {
token: string;
user: User;
}
interface LoginResponse {
success: boolean;
message: string;
data: LoginData;
}
import axios from "axios";
interface User {
id: number;
name: string;
email: string;
role: "admin" | "teacher" | "student";
}
interface LoginRequest {
email: string;
password: string;
}
interface LoginResponse {
success: boolean;
message: string;
token: string;
user: User;
}
const login = async (
data: LoginRequest
): Promise<LoginResponse> => {
const response =
await axios.post<LoginResponse>(
"https://example.com/api/login",
data
);
return response.data;
};
const handleLogin = async () => {
const data: LoginRequest = {
email: email,
password: password
};
try {
const result =
await login(data);
if (result.success) {
console.log(
"Token:",
result.token
);
console.log(
"User:",
result.user.name
);
console.log(
"Role:",
result.user.role
);
}
} catch (error) {
console.log(
"Login failed"
);
}
};
LoginRequest
↓
Axios POST
↓
PHP Login API
↓
Verify Email + Password
↓
LoginResponse
↓
TypeScript checks structure
↓
Get Token + User
↓
Update AuthState
↓
Send Bearer Token
↓
Protected API
A well-defined LoginResponse interface makes the communication between the React Native application and PHP REST API easier to understand, maintain, and debug.
Question: Which Axios syntax correctly tells TypeScript that the API returns a LoginResponse?