Assignment 3: Angular, TypeScript,
Bootstrap, Responsive Design, JavaScript in
Server Side, Node.js, Express, AJAX, JSON,
and Artsy API
1 Objectives
1. Get experience with creating backend applications using JavaScript/Node.js on the server side
with framework.
2. Get experience with using Angular, TypeScript, and Bootstrap on the client side and creating
responsive frontend.
3. Get experience with using HttpClientModule of Angular for AJAX.
4. Get experience with Artsy API.
5. Get experience with Google Cloud Platform (GCP).
2 Assignment Description Resources
1. Assignment Description Document (This document)
2. Rubric (aka, Grading Guidelines)
3 General Directions
1. The backend of this Assignment must be implemented in JavaScript using Node.js Express
framework (or Fastify/hono.js/ElysiaJS – however limited TA/CP support will be available). Refer
to Node.js website for installing Node.js and learning how to use it. Have a look at “Getting
started” guides in Express website to learn how to create backend applications using Express.
Axios and other libraries can be useful to make requests from your Node.js backend to Artsy
servers. Implementing the backend in anything other than Node.js will result in a 4-point
deduction.
2. The frontend of this Assignment must be implemented using the Angular framework. Refer to
Angular setup docs for installing Angular and creating Angular projects. Angular “Tour of
Heroes” app tutorial is a very good tutorial to see different Angular concepts in action.
Implementing the frontend in anything other than Angular will result in a 4-point deduction.
3. You are expected to create a responsive website. For that reason, we require you to use
Bootstrap, a CSS framework for responsive, mobile-first web development. It will save you from
the burden of dealing with CSS peculiarities (Some of you may have felt like this in Assignment
2) and the website you create will be responsive automatically if you develop within the
framework provided by Bootstrap. Please refer to Bootstrap docs for reference (especially look
1
at “Layout” section, and the components that you want to use). Refer to this post to learn how
to add Bootstrap to Angular projects. Not using Bootstrap will result in a 4-point deduction.
4. The backend of this Assignment must be deployed on Google Cloud. The backend should serve
the frontend as well as other endpoints you may define. Please refer to the instructions on D2L
Brightspace for deploying Node.js applications to any of the cloud services.
5. You must refer to the Assignment description document (this document), rubric, the reference
videos and instructions in Piazza while developing this Assignment. All discussions and
clarifications in Piazza related to this Assignment are part of the Assignment description and
grading guidelines. Therefore, please review all Piazza threads before submitting the
assignment. If there is a conflict between Piazza and this description and/or the grading
guidelines, answers and clarifications in Piazza supersede the other documents.
6. The Assignment will be graded using the latest version of the Google Chrome browser.
Developing the Assignment using the latest version of Google Chrome is advised.
4 Description
In this Assignment, you are going to create a web page that allows its users to search for artists using the
Artsy API. The results of the search will be listed as a list of artist cards. When a user clicks on an artist
card, details about the chosen artist will be shown underneath. The details will contain two tabs, one
containing information about the artist (name, birthday, deathday, nationality and biography) and other
containing artist’s artworks. Each artwork belongs to several categories which will be shown when the
categories button below the artwork is clicked.
4-1 Artsy Developer Registration (Same as Assignment 2).
To use Artsy API, you need to create a developer account in Artsy, create an app and get a client ID and
a client Secret.
Download the PDF file named Artsy REST API Setup from D2L Brightspace to create an account, obtain
the credentials to use the Artsy APIs, and test the APIs using Postman.
4-2 Artsy API Endpoints
The full list and documentation of Artsy API endpoints is given in https://developers.artsy.net/v2/. In
this Assignment, you will use 5 Artsy API endpoints: Authentication, Search, Artists, Artworks, and
Genes. The Artworks and Genes API endpoints are new. Also, some endpoints will be used for multiple
purposes – with different sets of parameters. The Authentication, Search and Artist endpoints are the
same as the ones used in Assignment 2.
Search, Artists, Artworks, and Genes endpoints require the X-XAPP-Token header, which you will get
through the Authentication endpoint.
4-2-1 Authentication Endpoint (Same as Assignment 2)
You can find the details about this endpoint in Assignment 2.
4-2-2 Search Endpoint (Same as Assignment 2)
You can find the details about this endpoint in Assignment 2. As per Assignment 2, only entities of type
“artist” should be returned.
2
4-2-3 Artists Endpoint (Same as Assignment 2)
You can find the details about this endpoint in Assignment 2.
You will use an additional variant (/artists) of this endpoint for similar artists.
Example request: https://api.artsy.net/api/artists?similar_to_artist_id=4d8b928b4eb68a1b2c0001f2
4-2-4 Artworks Endpoint
The Artworks endpoint is used to get a list of artworks that belong to other entities (i.e., artists,
partners, shows, collections, users). In this Assignment, we are interested in retrieving the artworks of a
specific artist. The Artworks endpoint has the base URL https://api.artsy.net/api/artworks. You send
your request using the HTTP GET method. The request accepts a query parameter artist_id denoting the
ID of the artist, artworks of which are being retrieved. Like the search endpoint, the maximum number
of results can be set by the size parameter, which has the maximum value of 10. In this Assignment, you
will always set it to 10. Like the search and artists endpoints, you should set X-XAPP-Token header in
your request to the token returned from the Authentication endpoint.
Note: this search request may take several seconds to return results.
Example request: https://api.artsy.net/api/artworks?artist_id=4d8b928b4eb68a1b2c0001f2&size=10
The server returns a JSON result like the sample given below.
3
The artworks are listed in [“_embedded”][“artworks”] field. We are interested in [“id”] (ID of the
artwork), [“title”] (name of the artwork), [“date”] (creation year of the artwork) and
[“links”][“thumbnail”][“href”] (image of the artwork) fields of each artwork result.
Similar to search results, artworks results are paginated, meaning that the endpoint returns a specific
number of results after each request (set by the size parameter) and if the remaining results are wanted,
another request can be made to the link in the [“_links”][“next”][“href”] field of the response. In this
Assignment, you will only use results from the first page and will not make additional requests.
4-2-5 Genes (Categories) Endpoint
The Genes endpoint is used to get metadata about artists or artworks in Artsy. You will use it to get
metadata about artworks. Since gene is a strange word for this context, we use the word “category”
instead. The Genes endpoint has the base URL https://api.artsy.net/api/genes. You send your request
using HTTP GET method. The request accepts a query parameter artwork_id denoting the ID of the
artwork for which categories are being retrieved. Like the search, artists and artworks endpoints, you
should set the X-XAPP-Token header in your request to the token returned from Authentication
endpoint.
Example request: https://api.artsy.net/api/genes?artwork_id=515b0f9338ad2d78ca000554
The server returns a JSON result like the example given below.
4
5
The categories are listed in [“_embedded”][“genes”] field. We are interested in [“name”] (name of the
category) and [“_links”][“thumbnail”][“href”] (image of the category) fields of this response.
Similar to search and artworks results, gene results are paginated, meaning that the endpoint returns a
specific number of results after each request (set by the size parameter) and if the remaining results are
wanted, another request can be made to the link in the [“_links”][“next”][“href”] field of the response.
In this Assignment, you will only use results from the first page and will not make additional requests.
4-3 Gravatar Service Overview
In this assignment, we will work with users and display their profile. Avatar is part of it. Some services
have a functionality to upload profile pictures, however this could be very cumbersome. Instead, we will
use a public profile pictures service!
Gravatar is an open service designed to store user public avatars and user public profiles. It is integrated
into many services, including Wordpress. You will show the gravatar’s profile image of a user in this
assignment. There is no need to call any APIs from the backend. Instead gravatar matches the avatar by
hash of the email, so you will need to calculate a SHA1 hash and form the correct image URL. You will
need to generate and store this URL on the backend and return it to the frontend as part of the user's
profile (see Authentication section).
If there is no avatar image matched, the service will generate a distinguishable visual pattern. More
details and examples can be found at https://docs.gravatar.com/api/avatars/images/ .
4.4 System Overview (Similar to Assignment 2)
The system contains three components: 1) browser (frontend), 2) Node.js/Express application (backend)
and 3) Artsy servers. You will implement the frontend and the backend. Your backend will have two
pieces of functionality: serving the frontend static files to the browser and responding to the frontend's
AJAX requests by fetching data from the Artsy servers. You will not directly call Artsy API from the
frontend JavaScript, as it requires disclosing Client Id and Client Secret (and/or XAPP_TOKEN) to the
public. The data flow diagram after an AJAX call is shown below.
Sending a front-end request (that returns data) to any service except your backend will result in a 4-
point penalty. Please do not directly call the Artsy API endpoints from your frontend.
All requests from frontend to backend must be implemented using the HTTP GET method, as you will
not be able to send us sample backend endpoint links as a part of your submission if you use HTTP POST.
Frontend Backend
Artsy API
MongoDB
Data flow:
6
4-5 Database
In this assignment we will store users and their preferences in a database. For these purposes, we will
use a NoSQL database, MongoDB. MongoDB is also available as a Cloud Service, called MongoDB Atlas.
MongoDB Atlas is a source-available, cross-platform, document-oriented, DBMS. It is classified as a
NoSQL DBMS (NoSQL Database Management System). A NoSQL DBMS is a non-relational database that
is designed to handle large-scale, distributed, and flexible data storage. Unlike traditional SQL
(relational) databases, NoSQL databases do not require fixed schemas, tables, or structured
relationships.
MongoDB Atlas uses JSON-like documents with optional schemas. For more information, see:
https://www.mongodb.com/docs/
Also, see MongoDB on Google Cloud: https://www.mongodb.com/mongodb-on-google-cloud
Once you set up an account in MongoDB Atlas, you will have to create a project to store your databases.
Below are the steps to set up a project and create a database.
Follow these steps to create a project in which you can store databases for your application.
Follow these steps to create a deployment for the project by creating a cluster and providing user
access and network access for the same. This would allow your application, running on a different
server, to connect to MongoDB Atlas in the cloud.
7
Follow these steps to create a database and a collection in that database. MongoDB stores data records
as documents (specifically in BSON format) which are gathered in collections. A database stores one or
more collections of documents.
Follow these steps to provide the instructions on how to connect to your MongoDB database from your
application.
Once you have set up the database and the collection, you can connect to the database by adding the
MongoDB node driver to your application. For more information on how to add the driver and run
queries on the database, refer to MongoDB Node Driver — Node.js.
Make sure to set up accesses in the “Database Access” and “Network Access” side menu to give proper
access to your client and allow certain IP addresses to access your database and collection(s). We
recommend creating a dedicated user that will only have “ReadWrite” access to your collection(s) and
set up an IP filtering such that it would match your IP for local development and the IP of cloud
deployment. WE DO NOT RECOMMEND HAVING 0.0.0.0/0 entry – this will allow anyone to try and
access your MongoDB instance.
4-6 Authentication
In this assignment we will support two types of clients: Guests and Authenticated users. Part of the
functionality will be available (and visible) only to users that are logged in. In short, authenticated users
can (in addition to guest users’ privileges):
1) See “similar artists” section
2) Have a favorite list of artists (separate favorites page and add/remove buttons)
You will need to implement 4 actions (endpoints):
1) Registration (available only to guests)
2) Login (available only to guests)
3) Log out (available only to authenticated users)
4) Delete account (available only to authenticated users)
Moreover, your frontend should track (know) if the user is logged in and show information about
current user (if any).
Auth functional requirements:
1) Auth state should be persistent across page reloads (F5/Cmd+R)
2) Auth state should be shared across tabs
3) Information belonging to user (Profile, favorites) should match the current user
4) Log out functionality should permanently change the auth state (ex: if you log out and reload
the page, you should be still logged out, regardless of the tab)
5) Visible elements should respect the state of authentication (elements that are only available to
logged users should be hidden on log out and vice-versa)
In this assignment we will use JWT tokens and Cookies.
4-6-1 Registration Procedure
The frontend should send a request to the backend containing all the fields necessary to register a user.
The backend should validate the data. If there is another registered user with the same email or some
fields are missing or contain incorrect values (though most of these errors should be caught on the
frontend, see below discussion), a proper error message should be returned. The frontend will rely on
this message to display all validation errors for the corresponding fields.
Also, the backend should generate a profile image URL. Please refer to the Gravatar Section and
Gravatar’s documentation. https://docs.gravatar.com/api/avatars/hash/ . Be advised, that you can use
Node.js’s built-in “node:crypto” module to create a sha256 hash.
The backend should insert the user’s data into the database. Users’ data should minimally contain the
following fields (you may change their names): fullname, email, password (hashed), profileImageUrl. You
may have additional fields if necessary.
Storing passwords in plaintext in the database is not secure! To prevent passwords from leaking they are
stored in an irreversible hashed form. One of the popular secure hash algorithms is bcrypt. One of the
recommended implementations is the “bcrypt” npm package. Please refer to its documentation:
8
9
https://github.com/kelektiv/node.bcrypt.js?tab=readme-ov-file#esm-import
After the user’s information is inserted in the database, we need to create and return the JWT token to
the frontend. In this assignment we will use cookies to set, store and send these tokens. Token and
cookies should be set to be valid for 1 hour.
The registration page (and the menu) should be available to unauthenticated users only and should
match the screenshot below.
The form should have validation – all fields are required (use the REQUIRED attribute), the email field
should contain a valid email address. This validation should be performed on the client (use the
PATTERN attribute). Additionally, validation errors coming from the backend should also be shown
under a corresponding field (please refer to the screen shot). Validation errors disappear once the field
value has been modified (and does not contain a frontend-checked error anymore). The “Register”
action button should be disabled while the form is empty or contains validation errors.
The login link should lead to the login page, as shown in the next page.
4-6-2 Login Procedure
The front end should send the email and password to the backend, once validation checks have been
successful. The backend should look for a user matching the email and the password sent against the
stored email and hash associated with the user. If the user is not found or the password does not match
an error should be returned and properly shown on the frontend (refer to the screenshots below).
If a user is found and the password matches the hash, the user should be authenticated by responding
with all required data to set up his session (maybe with user profile data). Like with the registration
process, use a JWT token and HTTP-only cookies with expiration offset set at 1 hour (for both JWT and
the cookie).
The login page (and the menu) should be available to unauthenticated users only and should match the
screenshot below.
Form validation and behavior should be like the form described in the “Fixme-1. Registration” section –
all fields are required, email should be valid, “Login” button should be disabled until there are no
validation errors.
On a successful login, the frontend should redirect the user to the Search page and change the visual
appearance of all elements according to a new auth state (described below).
The Register link should lead to the registration page.
10
4-6-3 Logout Procedure
This menu should be available to authenticated users only and should match the screenshot below.
When an option is clicked, it should send a request to the backend to clear the cookie. Additionally, the
frontend should reflect a new unauthenticated state. If the user was previously on the page that
requires authentication, redirect to the Search page.
4-6-4 Delete account Procedure
This menu should be available to authenticated users only and should match the screenshot below.
When this option is clicked, it should send a request to the backend to delete the user with all data
11
associated and clear the cookie. Additionally, the frontend should reflect a new unauthenticated (guest)
state. If the user was previously on the page that requires authentication, redirect them to the Search
page.
4-6-5 Current auth state
Once the user logs in, the page refresh should not affect the frontend's auth state (until the user logs
out / deletes his profile)!
Frontend in the authenticated state must store some profile data (profile, favorites), hence after the
page is refreshed, the frontend should be able to restore that data. There could be different approaches:
1) “…/me” request (Recommended).
This approach suggests the following – once the page is loaded, the frontend immediately issues
a specific request to the backend. This includes an additional endpoint (usually “…/me”) that
tries to authenticate users based on the JWT cookie (if provided) and returns some state (could
be current user profile and maybe some other data) that usually has data like the “/login”
endpoint.
If there are no credentials provided (or they have expired/ are invalid) the corresponding
response indicates to the frontend that the current state is “unauthenticated”.
If user data is returned – frontend can just use this data and change auth state to
“authenticated”.
2) Local storage. We don’t recommend persisting user data in the localStorage, since it might be
impossible to determine the consistency of localStorage data against the data in the HTTP-only
Cookie (ex: it can be expired or cleared), since JS cannot read it. There are some workarounds,
however they could simply lower the security.
4-7 User Favorites
This assignment allows authenticated users to store a list of favorite artists. The backend should keep
this list associated with user (and store it in the database) and support the following actions:
1) Adding an artist to the user’s favorites list
2) Removing an artist from the user’s favorite list
3) Retrieving user’s favorites
The backend should also track the moment of time when the artist was added. Later, the frontend
should display them in the “newest-first” order.
Since the list is associated with the user, it should be deleted once the user is deleted.
This list will affect the appearance of certain elements, so it might be convenient to return this data
along with the user profile. In other words, the frontend should have this list (and maintain its
12
consistency) as soon as possible to correctly display artists’ state on the screen. Visual description is
provided in the corresponding section below.
4-8 Page Layout
The page contains a header section, a content section and a footer section arranged vertically.
The header section has a bar (Hint: Check Bootstrap navbar component) containing the site title “Artist
Search” on its left and a menu on the right. Items available in the menu depend on whether the user is
logged in or not.
For unauthenticated users - Search, Log In, Register:
For authenticated users - Search, Favorites and a profile dropdown:
Profile dropdown consists of a static part and a dropdown itself. Static part should have user’s avatar
(from Gravatar.com), full name and a caret. Click on the static parts triggers dropdown and it
opens/closes. Any click outside the dropdown, as well as the “ESC” key press closes the dropdown.
Dropdown consists of two items: “Delete account” and “Log out”. Those options are described in the
“FIXME-4 Authentication” section.
The footer section is another static bar containing Artsy attribution “Powered by Artsy.”, in which the
Artsy logo is placed before the word “Artsy”. When Artsy text on the footer is clicked, the page is
redirected to Artsy homepage.
Page Footer
The content section contains the contents of the page, in which the following features will be shown.
4-9 Search Form
When a user opens the page for the first time, there is only a search form (Hint: Check Bootstrap Forms)
in the content section. Search form contains three items: an input section, a search button and a clear
button, shown below.
Search Form
13
The behavior of the Clear button is described in Section 4-12.
The Search button is enabled if and only if the input section contains some input as shown below. (Hint:
check disabled attribute).
Search Button is Enabled when Input Section is not Empty
Artist names will be entered into the input section of the search form. The input section has the
placeholder value “Please enter an artist name.”, which is shown when the input field is empty. When
the input section is focused (i.e., input section is clicked and the cursor is blinking within the field), its
style changes as shown below.
Input Section when Focused
Users can initiate a search by either 1) clicking the search button or 2) by hitting the enter key. Users
cannot initiate search when the input section is empty because the search button is disabled.
Like Assignment 2, when the search is initiated, your frontend will do an AJAX call to the backend,
sending the input text. Upon receiving the request, your backend will make a request to Artsy Search
API, forwarding the input text to Artsy Search API via parameter q as described in the Search Endpoint
section above. Until a response is received from the backend, a spinner (Hint: Check Bootstrap spinners)
will be shown near the search button as shown below.
Spinner is Shown Until a Response Arrives
When the response arrives, the spinner will be hidden, and the results are shown in the result list.
The clear button of the search form brings the page to its initial state. It clears the input section, result
list and artist details. Consequent page refresh shows the initial state of a cleared page.
4-10 Result List
The results of the search are shown as a list of cards (Hint: Check Bootstrap Cards), similar to
Assignment 2. Each card contains the artist image with link retrieved from the
["_links"]["thumbnail"]["href"] field of an artist resulting in the response of search endpoint. Below the
image, the artist’s name is listed corresponding to the [“title”] field of the artist result. The list of result
cards is scrollable. The artist names have a blue background color (HTML Color Code: #205375).
14
Result List
If a particular artist does not have an image, Artsy returns “/assets/shared/missing_image.png” in the
["_links"]["thumbnail"]["href"] field as mentioned in Section 4-2-2. In this case, you will place Artsy logo
as the artist image as shown below.
Artsy Logo is Shown if an Artist Does Not Have an Image
If the search results are empty, i.e. no artists match the given query, an error message containing text
“No results.” will be shown as below (Hint: Check Bootstrap Alerts).
No Artists Match the Query
When a card is hovered, its background color changes as shown below.
15
The Background Color Change of a Hovered Card
When the user is authenticated, the artist card should contain a button with a star icon. If the artist is
not in favorites, the star should have no fill. If the artist is in favorites – start should have a yellow fill.
Click on the button toggles the state – adds and removes an artist to/from favorites. This change should
be reflected immediately everywhere it is shown (for example, in the Artist Info tab) and trigger the
notification logic described in the favorites section below.
The “favorites” button appearance and on-off states
When an artist card is clicked, your frontend will do an AJAX call to your backend to get artist details. To
get artist details, you must send an artist ID to the backend. For that, you must associate artist IDs with
cards, which you can do during initial search by sending artist IDs from your backend to the frontend as
a part of the response. Detail view will contain two tabs – “Artist Info” (Selected by default) and
“Artworks” Until a response is received from the backend, a spinner is shown for both tabs as shown
below.
16
Spinner is Shown Until a Response Arrives
The selected card’s background color is permanently set to lighter blue after the click, which denotes the
active card for which details are being shown. It should stay the same until another card is selected or
details are closed (by clicking on “search” or “clear” buttons).
When the response with necessary data arrives, hide the spinner and show the contents of a
corresponding tab.
4-11 Artist Details
Artist details are shown in two tabs: Artist Info and Artworks (Hint: Check Bootstrap Navs and Tabs).
4-11-1 Artist Info Tab
Artist Info tab contains the same information as Assignment 2. It includes artist name, artist birth year,
artist death year, artist nationality and artist biography retrieved from Artists endpoint as shown below.
17
Artist Info Tab
Artist Info formatting.
The first line contains the name of the artist. Next line contains the nationality of the artist, followed by
birth and death days. Notice the “en dash” between dates. Next, the biography is shown. Notice proper
paragraph separation and no split words for a line break (See “By 1911-12, Cubism”. Original text: “By
1911–12, Cub- ism”).
18
This information corresponds to [“name”], [“birthday”], [“deathday”], [“nationality”] and [“biography”]
fields of the artist's endpoint response. Similar to Assignment 2, if any of the fields are empty, you
should simply leave them blank.
If content does not fit the screen, the whole page should be scrollable.
Open description (tabs and their contents) should be restored after the page refresh, however search
results should hide, and search input should reset. You should design and implement it the way, one
may easily share the description with others (e.g. via socials) by url only (the page url should contain
enough information for frontend to restore the page state).
For authenticated users there are two main changes – a “star” button and similar artist section.
The “star” button should behave like the “star” button on an artist card.
Two states of the “star” button – not in favorites, in favorites
Under the description with biography there should be a block titled “Similar Artists”. Please use the
corresponding artsy endpoint to get the list from your backend. Similar artists should be displayed in the
form of cards that should look and behave exactly as artist cards in the search result section. You can use
the same frontend components. Upon click (except on the star button), they should change the content
of sections above to the artist from the card. Leave search results unchanged (but reset selected state if
description does not match the artist currently being displayed).
Screenshot of the artist detail section under authenticated user
19
4-11-2 Artworks Tab
The Artworks tab contains the artworks of the selected artist. Artworks are retrieved from the Artworks
endpoint described in Section 4-2-4. Example is shown below.
First Four Artworks of Claude Monet (Page Contains More)
Each artwork has an image corresponding to the [“links”][“thumbnail”][“href”] field of the artwork (See
Section 4-2-4), a name corresponding to the [“title”] field of the artwork (See Section 4-2-4) and a
creation year corresponding to the [“date”] field of the artwork (See Section 4-2-4). Artworks are listed
using Bootstrap Cards.
If an artist does not have any Artworks in Artsy, you should show an error message containing text “No
artworks.” as shown below.
Artist does not have any Artworks
A “Categories” button below each artwork opens a modal (Hint: See Bootstrap Modals) in which
categories for the artwork retrieved from the Genes Endpoint (See Section 4-2-5) are shown.
4-11-3 Categories Modal
The category modal has a title and a content section separated by a line as shown below.
20
Categories Modal Sections
The title section contains the image of the artwork, name of the artwork and creation date of the
artwork. The Content section contains the categories of the artwork retrieved from the Genes Endpoint.
Each category has a name corresponding to the [“name”] field of the gene (See Section 4-2-5) and an
image corresponding to the [“_links”][“thumbnail”][“href”] field of the gene (See Section 4-2-5).
When the “Categories” button of an artwork is clicked, the modal is opened, and a request is sent to the
backend to retrieve the categories (or genes) of an artwork. To get categories, you must send artwork ID
to the backend. You can associate artwork IDs with “Categories” buttons using the IDs provided by the
Artworks endpoint.
Until a response arrives, a spinner is shown in the content section of the modal as shown below. Spinner
is replaced by the categories when the response arrives. Each category is shown using a Bootstrap Card.
21
Spinner is Shown until Categories Response Arrives
If a particular artwork does not have any categories, an error message containing the text “No
categories.” Is shown in the content section of the modal.
4-12 Clear Button of the Search Form
The clear button of the search form brings the page to its initial state. It clears the input section, result
list and artist details as shown below.
Before and After clicking the ‘Clear’ button
4-13 Favorites page
This page is only available to authenticated users.
While loading, a spinner should be shown as on the screenshot below. To improve user experience, the
list of favorite artists should be maintained, so on navigation from another screen, there should be no
loading from the server, hence no spinner. The loading should only occur on page (full) reload.
If there are no artist in favorites, a “No favorite artists” message should be shown.
No favorite artists message
If there are some artists in the list, they should be displayed as cards in the “newest first” order.
22
Favorites page cards
The Favorite artist card should contain the following information: full name, dates of birth and death,
nationality, interactive timer representing relative time of when the artist was added to the favorites
and a blurred background image (the same used on artist card in search results or in the similar artists
list).
The Interactive timer is a relative time expressed with words which is auto updated. Some examples: for
less than a minute, display “1 second ago”/”n seconds ago”; for more than a minute, but less than an
hour display “1 minute ago” / “n minutes ago”, etc.
The Card should support two interactions:
1) On “Remove” button click artist should be removed from the favorites list
2) On card click (except on “remove” button) user should be navigated to the “Artist Details” page
with the artist being displayed. Search bar should be empty and there should be no search
results. Both tabs should behave identically as they behave after artist details are being shown
after search and select.
4-14 Notifications
Application should show confirmation in form of a top-right corner stackable notification for the
following actions (with corresponding text and bootstrap style):
1) add to favorites – “Added to favorites” (style = success)
2) remove from favorites – “Removed from favorites” (style = danger)
3) logout – “Logged out” (style = success)
4) profile deletion – “Account deleted” (style = danger)
Notifications should be shown regardless of where the action has been made. These notifications should
be visible for 3 seconds and automatically removed afterwards. In addition user may click “X” button on
the left part of the notification to manually remove it. Notifications should stack vertically with the last
23
notification triggered being on the bottom of the stack and the earliest being on the top. The stack
grows from the top to the bottom of the page and persists between page navigations (not page reloads).
Notifications and the stack of notifications
4-15 Responsive Design
The webpage you develop must be responsive. One easy way to test responsive behavior is to use
Google Chrome Responsive Design Mode in the Developer Console. Here are some snapshots from an
iPhone 14 Pro Max using the Google Chrome Responsive Design Mode. All functions should work on
mobile devices.
24
25
5 Assignment Submission
In your Table of Assignments page (on GitHub Pages), update the Assignment 3 link to refer to your
deployed website of this assignment. Also, similar to Assignment 2, provide an additional link to one of
your cloud query entry points, below the homepage link. Your project must be hosted on Google Cloud.
Graders will verify that these links are indeed pointing to the cloud service.
26
Also, submit your source code file to D2L Brightspace as a ZIP archive. Include your frontend and
backend source code, plus any additional files needed to build your app (e.g., yaml file). The timestamp
of your last submission will be used to verify if you used any grace days.
6 Notes
● You cannot use jQuery for Assignment 3.
● You must use Bootstrap for Assignment 3. If Bootstrap is not used, a 4-point deduction will be
applied.
● Appearance of the webpage should be like the reference videos as much as possible.
● Artsy lacks information for a lot of artists. Here are some examples for testing:
o Pablo Picasso: Has every detail in Artist Info, has a single artwork.
o Vincent van Gogh: Has everything except biography in Artist Info, has 10 artworks.
o Yayoi Kusama: Has everything except death date (Since she is not dead) in Artist Info,
has no artworks.
o Claude Monet: Has every detail in Artist Info, has 10 artworks.
o Raphael: Has everything except biography in Artist Info, has 10 artworks, some of which
do not have categories.
7 Hints
• To allow your frontend to call the backend without triggering CORS issues, it's usually easier to
serve API endpoints under the same hostname with the /api/... prefix. This way, you don't
need to modify your frontend configuration before deploying your app to GCP. In this setup,
your frontend can call /api/... directly without specifying a fully qualified URL (e.g.,
fetch("/api/")), as the frontend's origin will automatically be used.
• For local development and debugging, you can enable proxying all /api calls to your backend
using the proxy.conf.json configuration file. Vite (which is part of the Angular toolkit) will
use this file to set up a proxy. Please refer to the documentation here:
https://v17.angular.io/guide/build#proxying-to-a-backend-server (For angular 17). Ensure your
backend is running before making requests.
• Formatting relative time is a complex task since different languages and countries have varying
rules and grammar. Browser JavaScript engines include a built-in internationalization module
called Intl. You can use the new Intl.RelativeTimeFormat('en', …) function to
correctly format time differences. Since your formatter should return different time units, you
may want to use a series of if statements to determine whether the time difference should be
displayed in seconds, minutes, etc.
• For global notifications, consider creating a separate service that stores current notifications and
removes them after 3 seconds. Then, create a component to render the list of notifications and
mount it in the top-level component (e.g., app.component.ts), ensuring it remains unaffected by
route changes. Avoid placing your notification component inside pages that are conditionally
displayed based on router outlet - mount it in a global layout instead.
• You can create an isLoggedIn RxJS Subject in the AuthService to allow different parts of your
app to react to authentication status changes. This can be useful for showing/hiding UI elements
and reloading the favorites list upon login.
27
• Consider using two backend middleware functions: authenticated and unauthenticated to
protect specific endpoints.
o The authenticated middleware should check for the presence of an authentication
cookie, validate the JWT, store the user identifier in the request context, and throw an
HTTP error if authentication fails. Use this middleware for protected routes like logout,
delete profile, and favorites.
o The unauthenticated middleware should block authenticated users from accessing
certain routes, such as login and register, by throwing an HTTP error if an auth cookie is
detected.
8 Static Resources
● You can find the Artsy logo required for this Assignment in D2L Brightspace.
● You may use any star and star-filled icons in svg format. For example:
https://fontawesome.com/icons/star?f=classic&s=regular
https://fontawesome.com/icons/star?f=classic&s=solid
28
Assignment 3: Angular, TypeScript,
Bootstrap, Responsive Design, JavaScript in
Server Side, Node.js, Express, AJAX, JSON,
and Artsy API
Grading Guidelines
Graders will test the homework using the latest version of Google Chrome.
Total Points: 15
Grading Guidelines
Page Layout (0.75 points)
● Header Bar
o Has a header bar that is visually similar to the reference (0.125 points)
o Header bar contains the “Artist Search” text on the left (0.125 points)
o Header contains the correct menu items and profile dropdown according to current
auth state. (0.25 points)
● Footer Bar
o Has a footer bar which contains the “Powered by Artsy” text with Artsy logo before
Artsy and is visually similar to the reference (0.125 points)
o When “Powered by Artsy” text is clicked, the Artsy homepage at https://www.artsy.net
is opened. (0.125 points)
Search Form (1 point)
● Search form has a correct layout, styling and positioning. Placeholder text “Please enter an artist
name.” is present in the input field. (0.125 points)
● Search button is disabled initially, is enabled when input is entered and is disabled again when
input is removed. When the input field is clicked, the border changes correctly. (0.125 points)
● The clear button resets the page. (0.25 points)
● Search is functional when the search button is clicked and the enter button is hit. (0.25 points)
● When an artist is searched, the spinner is shown in the search button until a response arrives
and is hidden afterwards. (0.125 points)
● When the response arrives, the result list is shown. (0.125 points)
Result List (2.25 points)
● Artsy logo is shown as an artist image if the artist does not have an image. (0.125 points)
● Result cards have correct styling (colors and spacing). (0.25 points)
● Result cards have correct positioning (margins). (0.125 points)
● Result list has correct styling and positioning (horizontally scrollable, cantered). (0.375 points)
● Artist names have correct styling. (0.125 points)
● Result card background color changes when hovered. (0.125 points)
● When a result card is clicked, spinner is shown in the correct place until a response arrives and is
hidden afterwards. (0.375 points)
● When a result card is clicked, its background is set to darker blue and any other card’s
background color is set to original blue. (0.25 points)
● When the response arrives, artist details are shown. (0.25 points)
● When the search results are empty, error containing text “No results found.” is shown. (0.25
points)
Artist Details Tabs (0.5 points)
● Artist Info and Artworks buttons have correct styling and positioning. (0.25 points)
● Artist Info and Artworks buttons are functional. (0.125 points)
● Active tab’s button’s background color is set correctly. (0.125 points)
Artist Details: Artist Info (1 points)
● Artist name is shown correctly. (0.125 points)
● Artist birth and death dates are shown correctly. (0.125 points)
● Artist nationality is shown correctly. (0.125 points)
● Artist biography is shown correctly. (0.125 points)
● Page refresh.(0.125 points)
● Similar artists is visible if authenticated.(0.125 points)
● Similar artist cards open artists and show correct info.(0.125 points)
● Toggling favorites is reactive and reflects everywhere (eg: click on search result star also turns
star in artist detail>full name).(0.125 points)
Artist Details: Artworks (2.5 points)
● When an artist does not have any artworks, an error contains text “No artworks.” is shown.
(0.25 points)
● Artwork cards have correct styling. (0.25 points)
● Artwork cards have correct positioning. (0.25 points)
● Categories buttons open the modal for categories for the corresponding artworks. (0.25 points)
● Spinner is shown in the content section of the categories modal while the data is being fetched,
and the spinner is hidden after the response arrives. (0.25 points)
● Categories modal title styling is correct (image, name, date) (0.25 points)
● Category cards have correct styling. (0.25 points)
● Category cards have correct positioning. (0.25 points)
● Categories modal has a close icon on top right, which closes the modal when clicked. (0.125
points)
● Categories modal closes when somewhere outside of it is clicked on the page. (0.125 points)
● If an artwork does not have a category, an error containing text “No categories.” Is shown. (0.25
points)
Authentication (1.25 points)
● Registration basic validation & register button disabled state. (0.125 points)
● Registration validation – existing email. (0.125 points)
● Login basic validation & login button disabled state. (0.125 points)
● Login validation – incorrect credentials. (0.125 points)
● Auth state survives refresh. (0.25 points)
● Header dropdown actions (log out & delete profile) are functioning properly. (0.25 points)
● Notifications (login, logout). (0.25 points)
Favorites (1.75 points)
● Adding/removing triggers notifications. (0.25 points)
● Notifications can be closed manually. (0.125 points)
● List shows artists. (0.25 points)
● Empty list shows error message. (0.25 points)
● Artist card leads to artist detail page and shows correct content. (0.25 points)
● Order is “Newer-first”. (0.125 points)
● Relative time is updated every second. (0.125 points)
● Relative time has correct format and honours singular-plural forms. (0.125 points)
● The Favorites page has a spinner and loads correctly on page refresh (F5, Cmd+R). (0.125 points)
● Favorites are not shared between different users. (0.125 points)
Different Use Cases (2 points)
● When the user clicks on another search result while the details of another one are being shown:
o Existing details are hidden (0.25 points)
o Spinner is shown in the correct place until a response arrives and is hidden afterwards
(0.125 points)
o The background color of the newly selected card is set to darker blue, background color
of all other cards are set to original blue (0.125 points)
o The details of the newly selected artist are shown correctly (0.25 points)
● When the user searches for a new artist while the details of an artist are being shown:
o Existing details are not hidden (0.125 points)
o Existing result list is not hidden (0.125 points)
o The background color of the currently selected artist will not be changed (0.125 points)
o Spinner of the search button is shown in the correct place until a response arrives and is
hidden afterwards (0.125 points)
o The result list is replaced with the new results once the response arrives (0.25 points)
● When a user searches a new artist using the search bar while search results are being shown
without any details:
o Existing result list is not hidden (0.125 points)
o Spinner of the search button is shown in the correct place until a response arrives and is
hidden afterwards (0.125 points)
o The result list is replaced with the new results once the response arrives (0.25 points)
Responsive Design (2 points)
● The design of the website is as shown in the reference video and the screenshots in mobile view
for iPhone 14 Pro Max. (1 point)
● All functionalities of the web page work in the mobile view correctly for iPhone 14 Pro Max. (1
point)
Point Reductions
● Not using GCP App Engine (or appspot.com subdomain) for both frontend and backend parts (-3
points)
● Frontend directly connects to Artsy instead of backend (-4 points)
● Bootstrap is not used (-4 points)
● Frontend is not implemented in Angular (-4 points)
● Backend is not implemented in Node.js (-4 points)
版权所有:编程辅导网 2021 All Rights Reserved 联系方式:QQ:99515681 微信:codinghelp 电子信箱:99515681@qq.com
免责声明:本站部分内容从网络整理而来,只供参考!如有版权问题可联系本站删除。