Parsing User JSON - ldco2016/microurb_web_framework GitHub Wiki

import { User } from "./User";
import { Eventing } from "./Eventing";

export class Collection {
  models: User[] = [];
  events: Eventing = new Eventing();

  get on() {
    return this.events.on;
  }

  get trigger() {
    return this.events.trigger;
  }
}

I am going to ensure that my class Collection has a fetch() method that will make a request to /users and retrieve all the different users that I have:

I first implemented this with Axios just so I could see what information I was going to get back from JSON Server. I needed to parse this stuff and turn each object that I get back into an instance of a user. To do so, inside the index.ts file I completed the following:

import axios from "axios";

axios.get("http://localhost:3000/users");

I then chained on a .then() statement that got called with some response object that is of type AxiosResponse like so:

import axios, { AxiosResponse } from "axios";

axios.get("http://localhost:3000/users").then((response: AxiosResponse) => {
  console.log(response.data);
});

Screen Shot 2021-08-08 at 9 29 05 PM

So you can see that when I make a network request over to that endpoint, I get back an array of objects and each object is going to have an id a name and an age.

So the object i get back essentially conforms to my UserProps interface. So I want to take objects that conform to that interface and use them to create different instances of users. So I just need to loop over the response, take each one of these objects and throw them into buildUser.

Back in my Collection.ts file, I now need to use Axios and probably make reference to the UserProps interface inside of here:

import axios from "axios";
import { User, UserProps } from "./User";
import { Eventing } from "./Eventing";

export class Collection {
  models: User[] = [];
  events: Eventing = new Eventing();

  get on() {
    return this.events.on;
  }

  get trigger() {
    return this.events.trigger;
  }

  fetch(): void {
    axios.get();
  }
}

The argument to get() is going to be the url that I want to make my request to. I could hardcode it in, but I will eventually have to dynamically specify that root url on the fly. So whenever we create an instance of class Collection I should have to pass in the root url that I want to make this request to and then I can reuse it for other types of records as well. So I will add in a constructor() and use the shortened syntax to receive a public variable called rootUrl with type of string like so:

import axios from "axios";
import { User, UserProps } from "./User";
import { Eventing } from "./Eventing";

export class Collection {
  models: User[] = [];
  events: Eventing = new Eventing();

  constructor(public rootUrl: string) {}

  get on() {
    return this.events.on;
  }

  get trigger() {
    return this.events.trigger;
  }

  fetch(): void {
    axios.get(this.rootUrl);
  }
}

And then I was able to reference that rootUrl inside the fetch() method axios request with this.rootUrl.

So now I can chain on a .then() statement, receive all that JSON data and turn each of those objects into an instance of a user like so:

import axios, { AxiosResponse } from "axios";
import { User, UserProps } from "./User";
import { Eventing } from "./Eventing";

export class Collection {
  models: User[] = [];
  events: Eventing = new Eventing();

  constructor(public rootUrl: string) {}

  get on() {
    return this.events.on;
  }

  get trigger() {
    return this.events.trigger;
  }

  fetch(): void {
    axios.get(this.rootUrl).then((response: AxiosResponse) => {});
  }
}

Then I have a response.data property inside that .then() statement and I want to run a loop over response.data because that is going to be the array of records that we get back from the JSON Server. I will do a forEach() on this thing and for every object inside there I will turn it into an instance of a user and add it to the models array like so:

import axios, { AxiosResponse } from "axios";
import { User, UserProps } from "./User";
import { Eventing } from "./Eventing";

export class Collection {
  models: User[] = [];
  events: Eventing = new Eventing();

  constructor(public rootUrl: string) {}

  get on() {
    return this.events.on;
  }

  get trigger() {
    return this.events.trigger;
  }

  fetch(): void {
    axios.get(this.rootUrl).then((response: AxiosResponse) => {
      response.data.forEach((value: UserProps) => {});
    });
  }
}

So I will take the value and stick into User.buildUser() which will create a user and then push it into the models array as mentioned above like so:

import axios, { AxiosResponse } from "axios";
import { User, UserProps } from "./User";
import { Eventing } from "./Eventing";

export class Collection {
  models: User[] = [];
  events: Eventing = new Eventing();

  constructor(public rootUrl: string) {}

  get on() {
    return this.events.on;
  }

  get trigger() {
    return this.events.trigger;
  }

  fetch(): void {
    axios.get(this.rootUrl).then((response: AxiosResponse) => {
      response.data.forEach((value: UserProps) => {
        const user = User.buildUser(value);
        this.models.push(user);
      });
    });
  }
}

Now I can test this out easily inside of index.ts like so:

import { Collection } from "./models/Collection";

I will create a new instance of a Collection like so:

import { Collection } from "./models/Collection";

const collection = new Collection("http://localhost:3000/users");

collection.fetch();

IMPORTANT NOTE: Right now I am not returning a Promise from collection.fetch(). I am going to rely upon the Eventing system to know whether or not an event has changed.

So after running the entire forEach() I will trigger a change event like so:

import axios, { AxiosResponse } from "axios";
import { User, UserProps } from "./User";
import { Eventing } from "./Eventing";

export class Collection {
  models: User[] = [];
  events: Eventing = new Eventing();

  constructor(public rootUrl: string) {}

  get on() {
    return this.events.on;
  }

  get trigger() {
    return this.events.trigger;
  }

  fetch(): void {
    axios.get(this.rootUrl).then((response: AxiosResponse) => {
      response.data.forEach((value: UserProps) => {
        const user = User.buildUser(value);
        this.models.push(user);
      });

      this.trigger("change");
    });
  }
}

Then back inside of index.ts, to get a notification of when this has been completed, I can add on an event handler like so:

import { Collection } from "./models/Collection";

const collection = new Collection("http://localhost:3000/users");

collection.on("change", () => {
  console.log(collection);
});

collection.fetch();

I console logged the entire collection and headed to the browser.

Screen Shot 2021-08-08 at 9 52 51 PM

I should be able to expand it, open up models and see all those different users:

Screen Shot 2021-08-08 at 9 54 57 PM

The users that I see in here are all the users reflected in my users.db file. The only problem now is that my users collection only works with users:

export class Collection {
  models: User[] = [];
  events: Eventing = new Eventing();
...

So I am going to have to turn this into a generic class to make it reusable.