我正在切换到角度使用新的HttpClient。
API am调用以一种格式返回json数据。我想获取这些数据并将其转换为适合UI使用的打字稿模型类。
之前我这样做的方法是使用map函数,例如
return this.httpClient.get(url, { headers: headers })
.map(mapFunction)
.catch(errorFunction);
在map函数完成转换api响应的繁重工作时,可以引入模型对象,例如:
const mapFunction =
(response: Response) => {
const data = response.json();
const contacts: Contact[] = [];
let i = 0;
for (const result of data.resourceResults) {
i = i + 1;
const contact: Contact = new Contact();
contact.role = result.r
对我而言,这看起来非常麻烦,我基本上正在寻找一种方法将对象从api响应类型映射到ui模型类型,而不必为每个请求使用自定义映射函数。
答案 0 :(得分:2)
如果没有明确指定需要映射的内容,就无法进行自定义映射。您可以告诉服务器端返回UI友好响应,或者您需要自己在客户端进行映射。
如果要在客户端映射响应,可以利用Typescript类,并使用其constructor
快速生成所需的项目:
export class Contact {
public name:string;
public roles:any;
constructor(name:string, roles: any) {
//specify your own constructor logic
this.name=name;
this.roles=roles
}
}
现在您可以在mapFunction
中写一下,将响应显式转换为Contact
列表。此外,您可以使用数组.map()
来迭代对象,而无需编写for循环:
public mapFunction = (response: Response) => {
const data = response.json();
const resource = data.resourceResults;
//map it
return resource.map(result => new Contact(result.n, result.r))
}
不管是否繁琐,我认为这是主观的。但绝对可以用更优雅的方式编写代码。
答案 1 :(得分:0)
我目前对角度完全不熟悉,但由于打字稿,这仍然适用。抱歉,我的伪角度代码。最简单的方法之一是将对象映射到接口。因此,如果我有JSON响应:
{
Id: 1,
Name: "Bob",
Age: 21
}
由于 TypeScript ,我可以创建一个匹配的界面:
export interface IPerson
{
Id: number,
Name: string,
Age: number
}
我可以将值作为界面传递,而不必将映射值传递给类。
return (this.httpClient.get(url, { headers: headers })) as IPerson;
当然,如果你必须扩展JSON,这不是正确的解决方案。
答案 2 :(得分:0)
我要根据@CozyAzure的响应添加更多示例。
带有接口的Typescript类(为了更好地通过应用读取):
interface MessageConfig {
MessageId?: Guid;
SentAt?: Date;
Status?: string;
Text?: string;
}
export class Message {
MessageId: Guid;
SentAt: Date;
Status: string;
Text: string;
constructor(config: MessageConfig) {
this.MessageId = config.MessageId;
this.SentAt = config.SentAt || new Date();
this.Status = config.Status || "Unread";
this.Text = config.Text;
}
}
一个实用程序函数,用于将数据映射到Message类:
export function mapMessage(message: any) {
return new Message({
MessageId: message.messageId,
SentAt: new Date(message.sentAt),
Status: message.status,
Text: message.text,
});
}
将服务器响应映射到单个消息的服务功能:
addMessage = (message: Message) => {
return this.http.post(API, message).pipe(
map((response: any) => {
if (response && response.success) {
const m = mapMessage(response.message);
return m;
}
throw new Error(response.errorMessage);
}),
catchError(error => {
return throwError(error);
}),
share()
);
};
服务功能,地图服务器对多个消息的响应:
getMessages = (): Observable<Array<Message>> => {
return this.http
.get(API)
.pipe(
map((response: any) => {
if (response && response.success) {
let messages: Array<Messages> = [];
if (response.count > 0) {
messages = response.messages.map(
message => mapMessage(message)
);
}
return messages;
}
throw new Error(response.errorMessage);
}),
catchError(error => {
return throwError(error);
}),
share()
);
};
所以,是的,有很多事情要做,但这就是我对这个想法进行了许多次迭代之后得出的结论。它是最容易复制和维护的,而且清晰易懂,而且相当干燥。我通常有多个API调用映射到同一类,因此5分钟的设置为每个其他API调用节省了很多时间。