包含它的 属性 returns 个对象

Included property returns object that it's included to

我正在使用 ASP.NET Core 2.1 中的 WebAPI 进行我的副项目。我正在使用 Entity Framework Core 2.1.

我有一个用户:

public class User : Account
{
    public UInt64 UserEmail { get; protected set; }
    public UserImage UserImage { get; set; }
    public virtual ICollection<Recipe> Recipes { get; set; }

    public User() { }

    public User(string nick, UInt64 login, byte[] salt, byte[] passwordHash,
        string restoreKey, UInt64 userEmail) : base(nick, login, salt, passwordHash, restoreKey)
    {
        UserEmail = userEmail;
        Role = "user";
    }

    public void Update(UInt64 login, UInt64 userEmail)
    {
        Login = login;
        UserEmail = userEmail;
        UpdatedAt = DateTime.UtcNow;
    }

    public void UpdatePassword(byte[] newPassword)
    {
        PasswordHash = newPassword;
        UpdatedAt = DateTime.UtcNow;
    }
}

和用户图片:

public class UserImage : Image
{
    public int? UserRef { get; set; }

    public virtual User User { get; set; }

    public UserImage() : base() { }

    public UserImage(string content) : base(content) { }
}

在我的 DbContext 中,我有这样的东西:

modelBuilder.Entity<User>()
            .HasOne(x => x.UserImage)
            .WithOne(y => y.User)
            .HasForeignKey<UserImage>(y => y.UserRef)
            .IsRequired(false);

我的服务中有一个方法 returns 一个用户和他的图片:

public async Task<User> GetAsync(int id)
    {
        var user = await _context.Users.GetById(id)
            .Include(x => x.UserImage)
            .SingleOrDefaultAsync();

        if (user == null)
            throw new CorruptedOperationException("Invalid id");

        return user;
    }

问题是,当我使用 Postman 获取用户时,我得到了这样的响应:

{
"userEmail": 2606810040825320252,
"userImage": {
    "userRef": 16,
    "user": {
        "userEmail": 2606810040825320252,
        "recipes": null,
        "nick": "MadBear123",
        "login": 10458175107962595193,
        "salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
        "passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
        "role": "user",
        "restoreKey": "Vub!@g17@kcP",
        "id": 16,
        "createdAt": "2018-10-14T11:11:43.9902857",
        "updatedAt": "2018-10-14T11:11:43.990384"
    },
    "imageContent": "/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjZ/jPZ6rHocDfFz4iNI19b3BU+FdFjYiEho2/5A6l8Mi53Eg4bIbkj3Sx/bi0/T/2dde0CP8AaL1xdvhK+i+w3EeiQCeR4r7bA2NMj3rtnLhScEyLtJZRt+a/2fH8S/Ha5t77wn4x+Hfiqy0q8neCHRrW8vL2dTpuq3bhbeOOWbcqQNshdDNI8kaRqzAkYXiT9tDxF8DLbxlp+peE9b8davp8b6fdaB4ZsL9LqKFZJI57m9lubJhp6o6JGYZojch2w8UIwzEpSneEd9OtjOPJDV7el/yP2V+Hv7VvhvxLrhcftfaTHYl5CkWpXfhhHwJJFCsBBG4OAp6Y57cVjfAL9rHwj4Y/Zx+HMM37YXwb0KSPw7pkLWep3OjF4X+zQp5J/wBJjbcGIXB5yQOtfLn7FH/BbZpPA0eqN8N/EXgLVoI7u5utD8f6nqVrDeRxh5B/Z15baNLFdyNiSMwlIpt6/LG6q7pa0T/gtFefD79kf4e3uo6h8CdBsdA8N2S2clz8ablL7Xo47GMFhpy6FJM8i5IKhSySoACzqm6fehG1rtFq0pXvZH4L/sdftNWH7OOo61f65pt94g0W7sWsY9OsPEUmky3N23EMjT2zrcxLFG9w6tGrK0gjjcFJHFdR8ef2620zXZtY+EPi/wCLWh3HisTy+JLbxFqqXVxb3MgdHe0voPLdoZI3QFJIw6vACXkDkD550T4a61qHmC3jhZmwCd3T9K0JPgT4vZvlsvM3DGVfj9a6oymlaK179TCXI37z07dD6k+B3/BT/VPF+ixt8dvGnxw+JMvhXVDqnhfQtP8AEUVnZ3FxPb/Zp5r69niuLhsQBo4lEbGP7ROysm+RJfIf21v2pNU/a++KknjTVJLiBZ4I9IhtL3xFNq1zp0NuCY4fOu5ZLuaNVkAEk5JJ3ruYoSeb8IfslfEDxEFa2t7W3C95p9nqewNaXxW/Z48caV4b0e21OOzm/s8zKskV2824OwY/KVG0jpkZJGAeAMaSjVlG8l87av5mcalGMrRa9L6L0Wx//9k=",
    "id": 10,
    "createdAt": "2018-10-16T05:45:42.4644513",
    "updatedAt": "2018-10-16T05:45:42.4645292"
},
"recipes": null,
"nick": "MadBear123",
"login": 10458175107962595193,
"salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
"passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
"role": "user",
"restoreKey": "Vub!@g17@kcP",
"id": 16,
"createdAt": "2018-10-14T11:11:43.9902857",
"updatedAt": "2018-10-14T11:11:43.990384"

}

就像你看到的那样,我得到了一个用户和他的图像,在这张图像中我(再次)得到了这个用户。 我希望得到这样的回复:

{
"userEmail": 2606810040825320252,
"userImage": {
    "userRef": 16,
    "user": null,
    "imageContent": "/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjZ/jPZ6rHocDfFz4iNI19b3BU+FdFjYiEho2/5A6l8Mi53Eg4bIbkj3Sx/bi0/T/2dde0CP8AaL1xdvhK+i+w3EeiQCeR4r7bA2NMj3rtnLhScEyLtJZRt+a/2fH8S/Ha5t77wn4x+Hfiqy0q8neCHRrW8vL2dTpuq3bhbeOOWbcqQNshdDNI8kaRqzAkYXiT9tDxF8DLbxlp+peE9b8davp8b6fdaB4ZsL9LqKFZJI57m9lubJhp6o6JGYZojch2w8UIwzEpSneEd9OtjOPJDV7el/yP2V+Hv7VvhvxLrhcftfaTHYl5CkWpXfhhHwJJFCsBBG4OAp6Y57cVjfAL9rHwj4Y/Zx+HMM37YXwb0KSPw7pkLWep3OjF4X+zQp5J/wBJjbcGIXB5yQOtfLn7FH/BbZpPA0eqN8N/EXgLVoI7u5utD8f6nqVrDeRxh5B/Z15baNLFdyNiSMwlIpt6/LG6q7pa0T/gtFefD79kf4e3uo6h8CdBsdA8N2S2clz8ablL7Xo47GMFhpy6FJM8i5IKhSySoACzqm6fehG1rtFq0pXvZH4L/sdftNWH7OOo61f65pt94g0W7sWsY9OsPEUmky3N23EMjT2zrcxLFG9w6tGrK0gjjcFJHFdR8ef2620zXZtY+EPi/wCLWh3HisTy+JLbxFqqXVxb3MgdHe0voPLdoZI3QFJIw6vACXkDkD550T4a61qHmC3jhZmwCd3T9K0JPgT4vZvlsvM3DGVfj9a6oymlaK179TCXI37z07dD6k+B3/BT/VPF+ixt8dvGnxw+JMvhXVDqnhfQtP8AEUVnZ3FxPb/Zp5r69niuLhsQBo4lEbGP7ROysm+RJfIf21v2pNU/a++KknjTVJLiBZ4I9IhtL3xFNq1zp0NuCY4fOu5ZLuaNVkAEk5JJ3ruYoSeb8IfslfEDxEFa2t7W3C95p9nqewNaXxW/Z48caV4b0e21OOzm/s8zKskV2824OwY/KVG0jpkZJGAeAMaSjVlG8l87av5mcalGMrRa9L6L0Wx//9k=",
    "id": 10,
    "createdAt": "2018-10-16T05:45:42.4644513",
    "updatedAt": "2018-10-16T05:45:42.4645292"
},
"recipes": null,
"nick": "MadBear123",
"login": 10458175107962595193,
"salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
"passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
"role": "user",
"restoreKey": "Vub!@g17@kcP",
"id": 16,
"createdAt": "2018-10-14T11:11:43.9902857",
"updatedAt": "2018-10-14T11:11:43.990384"

}

或类似的东西。我尝试使用 Include() 和(或不使用)virtual 来按照自己的方式工作,但我最终得到了这个。

更新

GetById() 的定义:

public static IQueryable<User> GetById(this IQueryable<User> value,int id)
     => value.Where(x => x.Id == id);

您可以在 GitHub 上找到完整的项目。我在 MB#20.

分支工作

对于循环引用,您无法在 EF Core 中对其进行控制。

对于一般处理,我们在Startup.cs中进行配置,如

.AddJsonOptions(options =>
{
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json
        .ReferenceLoopHandling.Ignore;
    options.SerializerSettings.ContractResolver =
        new CamelCasePropertyNamesContractResolver();
});

和用例:

var user = await _userService.GetAsync(id);
return Ok(user);

对于您的问题,您将 return 之前的 user 修改为 return Ok(user.ShapeData(fields));,这使得 JsonSerialize 无法知道其循环引用。

解决方法是,在转换为 ExpandoObject 之前,像

一样处理循环引用
public static ExpandoObject ShapeData<TSource>(this TSource source, string fields)
{
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }
    var result =JsonConvert.SerializeObject(source, new JsonSerializerSettings{
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    } );
    source = JsonConvert.DeserializeObject<TSource>(result);
    var dataShapedObject = new ExpandoObject();

    //your rest code
    return dataShapedObject;
}

更新

对于UserImage中的null,是由于您将属性指定为public string ImageContent { get; protected set; }造成的。

尝试自定义 DefaultContractResolver 以反序列化受保护的属性。

IncludePrivateStateContractResolver.cs

public class IncludePrivateStateContractResolver : DefaultContractResolver
{
    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        const BindingFlags BindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
        var properties = objectType.GetProperties(BindingFlags);//.Where(p => p.HasSetter() && p.HasGetter());
        var fields = objectType.GetFields(BindingFlags);

        var allMembers = properties.Cast<MemberInfo>().Union(fields);
        return allMembers.ToList();
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var prop = base.CreateProperty(member, memberSerialization);

        if (!prop.Writable)
        {
            var property = member as PropertyInfo;
            if (property != null)
            {
                prop.Writable = property.HasSetter();
            }
            else
            {
                var field = member as FieldInfo;
                if (field != null)
                {
                    prop.Writable = true;
                }
            }
        }

        if (!prop.Readable)
        {
            var field = member as FieldInfo;
            if (field != null)
            {
                prop.Readable = true;
            }
        }

        return prop;
    }
}

public static class TypeExtensions
{
    public static bool HasSetter(this PropertyInfo property)
    {
        //In this way we can check for private setters in base classes
        return property.DeclaringType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                                     .Any(m => m.Name == "set_" + property.Name);
    }

    public static bool HasGetter(this PropertyInfo property)
    {
        //In this way we can check for private getters in base classes
        return property.DeclaringType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                                     .Any(m => m.Name == "get_" + property.Name);
    }
}

用例:

public static ExpandoObject ShapeData<TSource>(this TSource source, string fields)
{
    var soureType = source.GetType();
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }
    var serializeSettings = new JsonSerializerSettings{
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    };
    var deserializeSettings = new JsonSerializerSettings{
        ContractResolver = new IncludePrivateStateContractResolver()
    };
    var result =JsonConvert.SerializeObject(source, serializeSettings );
    var castType = JsonConvert.DeserializeObject<TSource>(result, deserializeSettings);
    var dataShapedObject = new ExpandoObject();

我设法解决了我的问题。我将模型属性中的所有私有 setter 更改为 public 使用的陶周原始答案。

我的 ShapeData 方法:

public static ExpandoObject ShapeData<TSource>(this TSource source, string fields)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }

        var result = JsonConvert.SerializeObject(source, new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        });
        source = JsonConvert.DeserializeObject<TSource>(result);
        var dataShapedObject = new ExpandoObject();
        // rest of my code
    }

用户:

public class User : Account
{
    public UInt64 UserEmail { get; set; }
    public UserImage UserImage { get; set; }
    public virtual ICollection<Recipe> Recipes { get; set; }
    // rest of the code
}

用户图片:

public class UserImage : Image
{
    public int? UserRef { get; set; }

    public virtual User User { get; set; }

    public UserImage() : base() { }

    public UserImage(string content) : base(content) { }
}

返回数据示例:

{
"userEmail": 2606810040825320252,
"userImage": {
    "userRef": 16,
    "user": null,
    "imageContent": "/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjZ/jPZ6rHocDfFz4iNI19b3BU+FdFjYiEho2/5A6l8Mi53Eg4bIbkj3Sx/bi0/T/2dde0CP8AaL1xdvhK+i+w3EeiQCeR4r7bA2NMj3rtnLhScEyLtJZRt+a/2fH8S/Ha5t77wn4x+Hfiqy0q8neCHRrW8vL2dTpuq3bhbeOOWbcqQNshdDNI8kaRqzAkYXiT9tDxF8DLbxlp+peE9b8davp8b6fdaB4ZsL9LqKFZJI57m9lubJhp6o6JGYZojch2w8UIwzEpSneEd9OtjOPJDV7el/yP2V+Hv7VvhvxLrhcftfaTHYl5CkWpXfhhHwJJFCsBBG4OAp6Y57cVjfAL9rHwj4Y/Zx+HMM37YXwb0KSPw7pkLWep3OjF4X+zQp5J/wBJjbcGIXB5yQOtfLn7FH/BbZpPA0eqN8N/EXgLVoI7u5utD8f6nqVrDeRxh5B/Z15baNLFdyNiSMwlIpt6/LG6q7pa0T/gtFefD79kf4e3uo6h8CdBsdA8N2S2clz8ablL7Xo47GMFhpy6FJM8i5IKhSySoACzqm6fehG1rtFq0pXvZH4L/sdftNWH7OOo61f65pt94g0W7sWsY9OsPEUmky3N23EMjT2zrcxLFG9w6tGrK0gjjcFJHFdR8ef2620zXZtY+EPi/wCLWh3HisTy+JLbxFqqXVxb3MgdHe0voPLdoZI3QFJIw6vACXkDkD550T4a61qHmC3jhZmwCd3T9K0JPgT4vZvlsvM3DGVfj9a6oymlaK179TCXI37z07dD6k+B3/BT/VPF+ixt8dvGnxw+JMvhXVDqnhfQtP8AEUVnZ3FxPb/Zp5r69niuLhsQBo4lEbGP7ROysm+RJfIf21v2pNU/a++KknjTVJLiBZ4I9IhtL3xFNq1zp0NuCY4fOu5ZLuaNVkAEk5JJ3ruYoSeb8IfslfEDxEFa2t7W3C95p9nqewNaXxW/Z48caV4b0e21OOzm/s8zKskV2824OwY/KVG0jpkZJGAeAMaSjVlG8l87av5mcalGMrRa9L6L0Wx//9k=",
    "id": 10,
    "createdAt": "2018-10-16T05:45:42.4644513",
    "updatedAt": "2018-10-16T05:45:42.4645292"
},
"recipes": null,
"nick": "MadBear123",
"login": 10458175107962595193,
"salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
"passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
"role": "user",
"restoreKey": "Vub!@g17@kcP",
"id": 16,
"createdAt": "2018-10-14T11:11:43.9902857",
"updatedAt": "2018-10-14T11:11:43.990384"
}