Fritter Backend


Data Modeling

  1. concept: user

    header: User

    states

    username: User -> one String
    password: User -> one Password
    dateJoined: User -> one Date
    
  2. concept: chirp (aka post)

    header: Post

    states

    author: Post -> one User
    dateCreated: Post -> one Date
    content: Post -> one Content
    dateModified: Post -> one Date
    
  3. concept: chirper (aka friend)

    header: Friend

    states

    user: Friend -> one User
    friends: Friend -> set User
    
  4. concept: nests (aka circles)

    header: Nest[Item]

    states

    name: Nest -> one Name
    creator: Nest -> one User
    members: Nest -> set User
    posts: Nest -> set Item
    
  5. concept: group times

    header: Time[Object]

    states

    creator: Time -> one User
    group: Time -> one Object
    startTime: Time -> one Hour
    endTime: Time -> one Hour
    

Visual Data Model

app Fritter

concepts

User
Post
Friend
Nest[Post.Post]
Times[Nest.Nest]

The data representation model of my app


Fritter Repo

Fritter App


Reflection

One of the tradeoffs I struggled with was either implementing a lot of middleware, but exposing more endpoints with my collections, or creating a code base robust enough to handle some common errors and exposing less endpoints with my collections. I ended up choosing the later, since I decided to focus on making my endpoints only expose the most necessary functionality needed to fully implement my operating principles. For example, I prevent users from being able to GET all freets, all users, all times, and all nests. Instead, I check that a user trying to get all of a creator’s nests can only be the creator themselves (i.e. only the creator of the nests can see all of their nests). I also struggled where to place which middleware, like checking that the creator of a nest is a valid user. To prioritize modularity, I placed any user checks in the user middleware, nest checks in the nest middleware, and so forth.

In addition, in terms on implementation, I realized there was some tension between my code modularity and actual synchronizations. For example, I debated whether to sync the deletion of users and posts to my nests and friends. I decided to make a cohesive app, it was important for me to sync the deletion and also sync creations: when a user is created, a friend object to the FriendCollection is also immediately made. These synchronizations are also an example of how, rather than exposing the POST endpoints to users, I created a code base that would automatically handle creation/deletion to prevent duplicates, input errors, malicious attacks, etc.

In terms of my routes, specifically for friends, I had to decide what routes make the most sense in terms of RESTful design. I ended up choosing to create POST and DELETE routes to represent adding and removing a friend, but technically, in my implementation, these are just updates to a user’s friend object.

Lastly, some of the tradeoffs I noticed while working on were deciding what to delegate what concepts to actually implement in my backend versus what concepts to delegate to my frontend. I ended up deciding not to implement my profile, feed, or filtering concepts since they can represented as the data from calls to the endpoints of user, nest, post, times, and friend.