Angular + Golang: My First Competition Experience with the Combo

Recently I've been working on a Golang + Angular project for a competition. Quite interesting though I didn't finish my thoughts due to the limit of my usable time.
This is the online demo (Chinese language): Demo.
This is the source: Github Link
Quite challenging for me day to day. When looking at my commits I'd say it's really interesting.
Before I started development, I hadn't finished a golang project or an angular project. But as we all know, you don't need to be really smart to start working on those things. I mean, both of them are already polished frameworks for web development.

Commits on Sep 21, 2020

  1. backend and frontend initial version
  2. split codes into project files, made the connection info more secure by getting it from env

Finally found another person to join me (to take part in this a team should be consisted of at least 2 members), so I started the frontend code in Angular, the backend code in golang. Actually really smooth working using them. The code was just usable enough.

Commits on Sep 22, 2020

  1. session id implementation in login function
  2. error handling in a single file

Actually on that day I'd been thinking about how to implement the login interface. It seemed not really secure to rely on the cookie (then every people can log in to the same account across the world using exactly the same cookie).
So I added a restriction that a person can only use the session when the cookie and his remote address match with the data in the database.
Still hackable, but I'm learning, maybe someday I could do it more smartly.

Commits on Sep 24, 2020

  1. homepage editprofile link
  2. TODO: user relationship
  3. TODO: change user info
  4. split official API into another go file
  5. register: check duplicate user touching the official API
  6. TODO: Add Role in accounts database
  7. frontend component changes
  8. userSession type in backend
  9. no session id assigned to cookies when there's no session id returned
  10. user info API, homepage in frontend, array deletion

Mostly code spliting and TODOs. Initial versions were a mess to work on.

I wrote this code to delete a session from the session array:

func deleteFromArray(target []userSession, index int) []userSession {
    copy(target[index:], target[(index+1):])
    return target[:len(target)-1]
}

Basically I saw some other solutions about array element deletion. Preferred this one.
In golang, list appending is also different from how it is written in python or javascript. It is achieved by a global append() instead of a member function. Might be good since it's more universally usable on all list types.

Commits on Sep 25, 2020

  1. split the function fetching the session info and the remote address into a function for future multiple uses.
  2. user list component in frontend
  3. add user list link for admin role group
  4. we should not change the portraitUri when it's submited as an empty string
  5. add isAdmin to the returning object from userInfo
  6. no need in returning info from login route, since userinfo does the job
  7. login after finishing registration
  8. add isAdmin to the model
  9. edit self info API complete
  10. seperate API signature and requesting feature from the functions
  11. edit my info page and API

Some error fixes, code splitting. Added an admin role on this version.

Commits on Sep 26, 2020

  1. backend: queryUserDB function split from codes to keep it more readable
  2. frontend: edit other user's profile, and change the routes for profile changing pages.
  3. frontend: new component for editing other person's info
  4. User List and User Profile View in frontend
  5. backend API for seeing other users' profiles and editing them.
  6. user list feature

Added a user list feature and make use of the admin role. At that time I had been thinking about password changing feature, though I haven't done it today and the project has been submitted for some review.

Commits on Sep 27, 2020

  1. frontend: making user auth only triggered when needed using ngrx/store and ngrx/effects
  2. frontend: ngrx/effects added
  3. frontend: ng dependencies update
  4. frontend - ng update and ngrx added

Added @ngrx/store and @ngrx/effects for some global usable variable. Actually now I found it could be a niche. A member variable in a service is already available for all pages in tha app to use. And @ngrx/store is not available for all types of data. Maybe I haven't experienced a case where I really need them.

Commits on Sep 28, 2020

  1. backend: tangoing with official go sdk
  2. backend: registration debug
  3. backend: log the identification values for 401 debugging
  4. backend: comment a line
  5. backend: debug info for api
  6. backend: just deployed the backend to my server
  7. backend: panic when an internal error happens
  8. backend: fix the IP format err in login function
  9. backend: typo error
  10. backend: fixed a x-forwarded-for backend format error.
  11. backend: module building
  12. frontend: tests about RongCLoud IM finished. gonna working on it
  13. backend: ditch the use of defer
  14. frontend: wrong use of store, so I changed back and only let it store the data.
  15. backend: official api navi to sg center
  16. backend: dependencies update

On that day, I tried to deploy the backend on my server, but it failed. So I tried their official go sdk. Still not working. And I'd later find myself not needing the SDK.

Commits on Sep 29, 2020

backend: debugging register API

Was kinda off that day.

Commits on Sep 30, 2020

  1. backend: organize functions and sort them into member functions in types.go, simplify some sprams
  2. backend: split some functions and made them used by unique receivers

Membership functions are really good in golang, making the code really readable itself.

Commits on Oct 1, 2020

  1. frontend & backend: add as friend feature
  2. backend: user relation - waiting to be tested

User relation feature is not really complete to this day ;( I wish I had been working more on this one.

Commits on Oct 2, 2020

  1. backend: utilize some db.Prepare to prevent some edge cases like forgetting to escape characters
  2. frontend: blacklist option

fmt.Sprintf has a potential possibility of failing to escape the characters. Looking at this:

package main

func main() {
    // ...
    user := "'a user you cannot lose'"
    // ...
    _, err := db.Query(fmt.Sprintf(`SELECT FROM table WHERE user='%s';`, user))
    // ...
}

Then it'll return an error.

So something like this is always safer:

package main

func main() {
    // ...
    user := "'a user you cannot lose'"
    // ...
    qFmt, err := db.Prepare(`SELECT FROM table WHERE user=$1;`)
    checkErr(err)
    _, err = qFmt.Query(user)
    // ...
}

Commits on Oct 3, 2020

  1. backend: re-register if token area is not the same as the uri

Me trying to fix a problem encountered when we change our region.

Commits on Oct 5, 2020

  1. backend: get conversation - some json to unmarshal from sql
  2. all: send/read message, update conversation

Interfaces based on the need.

Commits on Oct 8, 2020

  1. basic single chat interface
  2. backend: fix a token error

Created a basic single chat interface which was far from complete. Hmm, I was worried because at that time I was near the deadline Oct 14, 2020.

Commits on Oct 12, 2020

  1. material integration && chat messages api

Had to integrate it with material, since I had almost no time to think about it. But yep, it enhanced the efficiency by a lot.
Also made use of ApplicationRef to get some variable from app.component.ts. When I come to think about it now, it's not the smartest usage. I could achieve the same thing using a service!

Commits on Oct 13, 2020

  1. read support, markdown support......

I was in a hurry, it was more than the log, I did these:

  1. Backend: A RESTFul API to mark a conversation as read.
  2. Backend: Delete the SDK which was not needed anymore.
  3. Backend: A RESTFul API for Logout (Basically clear the cookie).
  4. Backend: A member function to delete a session.
  5. Backend: Markdown support for message sending
  6. Frontend: Integrations with them

Markdown is a trend you cannot miss. I'm personally a fan of it.

Commits on Oct 14, 2020

  1. need define some env
  2. uploads
  3. get the abs path of the backend dir
  4. rongURI from
  5. readme
  6. fix some bugs
  7. image upload
  8. upload file api
  9. frontend update
  10. backend: recall message, make db a global var, set max open connections and max idle connections, delete some multiple db parameter,fix a validation error in login function, make session info getting a member function of userSession, friendship validation in chat, some QueryRow fix

Deadline day, so the log looked horrible. I was busy testing when my connections in the backend easily exceeded the limit.
I searched and tried db.Prepare. Sadly it just wouldn't work.
Finally I changed some single row Query(...) in to QueryRow(...), then the connection number became stable and reusable.

When you use Query(...) to query a single row matching the condition, if you do the Next only once, then the connection will stay there and won't close. In this case, you need to scan that into the target variable and Next till that query variable returns nothing. That's why Query(...) is only good for multiple-row querying.

Also, no difference between these two on the performance:
1. using db.Prepare, then db.Query
2. using db.Query directly

package main

func main() {
    // ...
    qVar, err := db.Query(`SELECT a FROM table WHERE b=$1;`, thing)
    checkErr(err)

    for qVar.Next() {
        // ...
        qVar.Scan(&targetVar)
        // ...
    }

    // The connection qVar uses will become reusable again once the loop ends, 
    // in other words, when qVar.Next() returns false
    // ...
}

Also, that uploading API is tricky, need to define a environmental variable to get the correct url after upload is done.

Commits on Oct 15, 2020

  1. frontend: no need in validating value in single chat
  2. trying to make single chat looking good in low resolution too
  3. accounts
  4. style change about the image in the chat
  5. serve from uploadPath
  6. fix
  7. path of uploaded

Some follow-up updates. Hmm, I started loving material UI. It really saved my time.
Also, it's in the first hours that I deployed the app on my server and served them via a CDN.

The development period has been not too long and I know I could've done better if I had squized out more time. For now, I'm fine with the result. Learned a lot, and I have to say, Angular and golang are really interesting in web development.