-
Notifications
You must be signed in to change notification settings - Fork 351
User representations don't match #6299
Description
This Improvement request (usability, performance, tech debt, etc.) affects these Traffic Control components:
- Traffic Ops
- Documentation
Current behavior:
The representations of Users are different depending on the API endpoint used to view them, e.g. /user/current uses the field roleName to hold the name of the User's Role, while /users shows the same information in the rolename property.
The current model for users (API v3.0, 4.0 makes some structural changes in some contexts) is such that requests and responses have different "shapes" depending on the request method - and some fields are even renamed between requests and responses.
A TypeScript model of Users in APIv3
export interface PostRequestUser {
addressLine1?: string | null;
addressLine2?: string | null;
city?: string | null;
company?: string | null;
confirmLocalPasswd: string;
country?: string | null;
email: string;
fullName: string;
gid?: number | null;
id?: never;
lastUpdated?: never;
localPasswd: string;
newUser?: boolean | null;
phoneNumber?: string | null;
postalCode?: string | null;
publicSshKey?: string | null;
registrationSent?: never;
role: number;
roleName?: never;
rolename?: never;
stateOrProvince?: string | null;
tenant?: never;
tenantId?: never;
tenantID: number;
uid?: number | null;
username: string;
}
interface PutRequestNotChangingPasswordUser {
addressLine1?: string | null;
addressLine2?: string | null;
city?: string | null;
company?: string | null;
confirmLocalPasswd?: never;
country?: string | null;
email: string;
fullName: string;
gid?: number | null;
id?: never;
lastUpdated?: never;
localPasswd?: never;
newUser?: boolean | null;
phoneNumber?: string | null;
postalCode?: string | null;
publicSshKey?: string | null;
registrationSent?: never;
role: number;
roleName?: never;
rolename?: never;
stateOrProvince?: string | null;
tenant?: never;
tenantId?: never;
tenantID: number;
uid?: number | null;
username: string;
}
export type PutRequestUser = PostRequestUser | PutRequestNotChangingPasswordUser;
interface ResponseUser {
addressLine1: string | null;
addressLine2: string | null;
city: string | null;
company: string | null;
country: string | null;
email: string;
fullName: string;
gid: number | null;
id: number;
lastUpdated: Date;
newUser: boolean | null;
phoneNumber: string | null;
postalCode: string | null;
publicSshKey: string | null;
registrationSent?: null | Date;
role: number;
stateOrProvince: null;
tenant: string;
tenantID?: never;
tenantId: number;
uid: number | null;
username: string;
}
export interface PutOrPostResponseUser extends ResponseUser {
/**
* This appears only in response to POST requests, or to PUT requests where
* the user's password was changed.
*/
confirmLocalPasswd?: string;
rolename?: never;
roleName: string;
}
export interface GetResponseUser extends ResponseUser {
confirmLocalPasswd?: never;
rolename: string;
roleName?: never;
}
export type User = PutRequestUser | PostRequestUser | PutOrPostResponseUser | GetResponseUser;
export interface ResponseCurrentUser {
addressLine1: string | null;
addressLine2: string | null;
city: string | null;
company: string | null;
country: string | null;
email: string;
fullName: string;
gid: number | null;
id: number;
lastUpdated: Date;
localUser: boolean;
newUser: boolean;
phoneNumber: string | null;
postalCode: string | null;
publicSshKey: string | null;
role: number;
roleName: string;
stateOrProvince: string | null;
tenant: string;
tenantId: number;
uid: number | null;
username: string;
}
export interface RequestCurrentUser {
addressLine1?: never;
addressLine2?: never;
city?: never;
company?: never;
country?: never;
email?: never;
fullName?: never;
gid?: never;
id?: never;
lastUpdated?: never;
localUser?: never;
newUser?: never;
phoneNumber?: never;
postalCode?: never;
publicSshKey?: never;
role?: never;
roleName?: never;
stateOrProvince?: never;
tenant?: never;
tenantId?: never;
uid?: never;
username?: never;
}
export type CurrentUser = ResponseCurrentUser | RequestCurrentUser;- requests use
tenantID, responses havetenantId - responses from POST requests and PUT requests where the password was changed include
confirmLocalPasswdbut GET representations never do - POST and PUT responses don't include
registrationSentbut GET requests always do - /users never shows
localUser, but /user/current always does - POST and PUT requests allow
newUserto benull, but that's actually not allowed in the database, and GET requests will always show an actual boolean value. Plus, ifnewUserwasnullin a POST or PUT to /users, it will benullin the response, but if it wasnullin a PUT to /user/current the response will properly show false like a subsequent GET - PUT to /user/current doesn't require any fields, not even those required by POST and PUT requests to /users, making it non-idempotent in violation of the HTTP spec
- PUT to /user/current literally doesn't work at all, see PUT /user/current doesn't work #6367
and then of course we have the pervasive issue where things are allowed to be missing from the request as a synonym for "null", but that's more an issue just because in TS/JS undefined and null are different, but Go makes no such distinction without jumping through some encoding/json.RawMessage hoops.
New behavior:
Users should be represented consistently in a single way throughout the API.