Exam 2023-08-20

Here you find sample answers and marking guidelines to the questions on the exam 2023-08-20.


Start by reading through all questions. Peter will not visit the exam. If you find any question unclear, ask the exam administrator (tentavakt in Swedish) to call Peter for clarification.

Max score is 25 points.

  • For grade 3, 40% of max score (10 points) is required
  • For grade 4, 60% of max score (15 points) is required
  • For grade 5, 80% of max score (20 points) is required

You are not allowed to use anything else except:

  • The computer you sit at to only answer the questions on this exam
  • A dictionary to translate to/from English from/to your native language
  • Pen and paper to sketch with (should not be submitted)

Write your answers in either English or Swedish. If you write your answers in Swedish, make sure to not introduce any translation confusement. Write proper sentences (spelling, upper/lower case characters, punctuation, etc.). Answers that do not do this good enough/are vague/are not understandable cannot receive full score on the questions,

Answers that are more or less copies of sample answers given to you or copies of text found somewhere else will be rewarded 0 points. Use your own words to answer the questions.

Good luck!

Client-Side JS

Question 1 (1p)

Question

In client-side JS, name three different methods we can call on the document object to obtain references to HTML elements on the webpage (the method should either return a single reference, or multiple references (i.e. a NodeList/Array)).

Sample answer

  • getElementById
  • querySelector
  • querySelectorAll

Marking guidelines

  • 0.33 points for each correct name
    • Only 0.23 if spelling is wrong

Question 2 (1p)

Question

Name two different events that can fire on a webpage and that cause the web browser to send an HTTP request to load a new webpage.

Sample answer

  • click (when a <a> element is clicked)
  • submit (when a <form> element is submitted)

Marking guidelines

  • 0.5 points for each correct event name

Question 3 (1p)

Question

Explain when and how many times the event DOMContentLoaded fires on a webpage.

Sample answer

The DOMContentLoaded event is fired by the web browser each time it has loaded a new webpage from the HTML code in an HTTP response, so it fires once for each webpage that is shown.

Marking guidelines

  • 0.5 point for when
  • 0.5 points for how many times

Frontend framework

Question 4 (2p)

Question

In a frontend framework of your choice (name which one you choose), implement a component that works like this:

  • The one using the component should be able to pass an array of integers to it
  • If the array is empty, the component should display an HTML paragraph with the text No integers
  • If the array is not empty, the component should display the integers in an HTML ordered list:
    • Each integer should be displayed in its own HTML list item
    • Each integer should be displayed as it is (e.g. 5 should be displayed as 5), except 0, which should be displayed as the text Zero

Sample answer

In Svelte:

<script>
    
    export let integers
    
</script>

{#if integers.length == 0}
    <p>No integers</p>
{:else}
    <ol>
        {#each integers as integer}
            <li>
                {#if integer == 0}
                    Zero
                {:else}
                    {integer}
                {/if}
            </li>
        {/each}
    </ol>
{/if}

Marking guidelines

  • 0.5 points for correct prop
  • 0.5 points for using if correct
  • 0.5 points for using loop correct
  • 0.5 points for using else correct
  • Point deductions for errors:
    • -0.1 points for using array.count/array.isEmpty instead of array.length
    • -0.25 points for using extra variables not needed/not used
    • -0.25 points for not using else, but inverted condition in an extra if
    • -0.5 points for not naming which framework that is used
    • -0.5 points for always showing <ul>
    • In Svelte:
      • -0.1 points for of instead of as in #each
      • -0.25 points for not using the { ... } syntax in Svelte
      • -0.25 points for not using #each correct
      • -0.25 points for using $ in front of variable name when it's not a store

HTTP/REST API

Question 5 (1p)

Question

Match each status code to its corresponding reason phrase.

Status codes:

  • 200
  • 201
  • 204
  • 404
  • 500

Reason Phrases:

  • Internal Server Error
  • No Content
  • Not Found
  • Created
  • OK

You will get:

  • 1 point for all correct

Sample answer

  • 200 - OK
  • 201 - Created
  • 204 - No Content
  • 404 - Not Found
  • 500 - Internal Server Error

Marking guidelines

  • 1 point for all correct

Question 6 (1p)

Question

In HTTP, explain when the Accept header can be used, what it represents, and give an example of a value it can have, and explain what using the header with that value means.

Sample answer

The Accept header can be used in an HTTP request to indicate which data format the client wants the body in the HTTP response to be written in. For example, the value application/json would mean that the body in the response should be written in JSON format.

Marking guidelines

  • 0.25 points for used in requests
  • 0.25 points for what it represents
  • 0.25 points sample value
  • 0.25 points for what sample value means

Question 7 (2p)

Question

On a backend storing information about species, the following relational database table is used to store the species:

idnamenumberOfLegs
1Snake0
2Dog4
3Human2
4Cat4
.........

Your task is to design a REST API clients can use to update a species with a specific id. The following validation rules should exist:

  • name must contain at least 1 character
  • Two different species with the same name may not exist
  • numberOfLegs must be 0 or more

Someone who implements or uses your API should be able to get all details they need to know about the API from your design, so be sure to mention all relevant details they need to use/implement it.

Note: You don't need to worry about authorization in this task; any (anonymous) client should be allowed to update any species.

Note: If you think you are missing some important information you have to know to be able to carry out the task in a good way, feel free to make your own assumptions about that information, but clearly state which those assumptions are in your answer.

Sample answer

Words WRITTEN_LIKE_THIS are placeholders for actual values.

Request:

  • URI: /species/THE_ACTUAL_ID
  • Method: PUT
  • Headers:
    • Content-Type: application/json
    • Content-Length: THE_ACTUAL_NUMBER_OF_BYTES_IN_THE_BODY
  • Body:
    {"id": THE_ACTUAL_ID, "name": "THE_ACTUAL_NAME", "numberOfLegs": "THE_ACTUAL_NUMBER_OF_LEGS"}
    

Possible responses:

  • If the server can't carry out the request because of some internal error:
    • Status code: 500
  • If there doesn't exist a species resource with THE_ACTUAL_ID:
    • Status code: 404
  • If the resource was successfully updated
    • Status code: 204
  • If there are validation errors:
    • Status code: 400
    • Headers:
      • Content-Type: application/json
      • Content-Length: THE_ACTUAL_NUMBER_OF_BYTES_IN_THE_BODY
    • Body:
      ["ERROR_CODE_1", "ERROR_CODE_2", ...]
      
      • Available ERROR_CODE_X:
        • NAME_TOO_SHORT (name must contain at least 1 character)
        • NAME_ALREADY_USED (a species with the new name already exist)
        • NUMBER_OF_LEGS_TOO_FEW (must be at least 0)

Marking guidelines

  • 0.5 points for request
  • 0.5 points for handling success response
  • 0.5 points for handling not found response
  • 0.5 points for validation errors response

Point deduction:

  • -0.1 points for each piece of information missing, such as:
    • URI in request
    • Method in request
    • Crucial header in request (except Content-Length)
    • Body/property in body
    • Crucial header in response
    • Error code/message
    • Etc.
  • -0.1 points for each piece of information written that makes no sense

Question 8 (3p)

Question

Name and describe each constraint REST consists of.

Sample answer

See Chapter 5.1 Deriving RESTopen in new window in Roy Thomas Fielding's dissertation Architectural Styles and the Design of Network-based Software Architectures.

Marking guidelines

  • 0.25 points for each correct name
  • 0.25 points for each correct description

Question 9 (2p)

Question

Alice is assigned the task to design a REST API clients can use to login and then create new blogposts belonging to that account. She decides that when a user logs in, the client obtains an access token (THE.ACCESS.TOKEN) containing the user's account id, which can be used to act on the behalf of that user. Then when the user wants to create a new blogpost belonging to her own account, the client sends an HTTP POST request to /blogposts with the headers Authorization: Bearer THE.ACCESS.TOKEN and Content-Type: application/json, and in the body pass {"title": "The actual title", "content": "The blogpost text."}.

Is this a good or bad design? Justify your answer.

Sample answer

It's a bad design, because the resource in the body of the request contains no information about which account the blogpost should belong to. In HTTP, the body should contain the entire resource, so if one for example logs the URI, method and the body on the server-side and look at it later, one should be able to understand what the entire request is about.

Alice is probably thinking the account id in the access token can be used to figure out which account the blogpost should belong to, but access tokens should only be used for authorization, and not containing a part of a resource, so the body should still contain a value that indicates which account the blogpost should belong to, and the account id in the access token should only be used to figure out if the user is allowed to create a blogpost belonging to that account (e.g. all users may create a blogpost belonging to their own account, but admins may also create a blogpost belonging to someone else's account, so one can't blindly use the account id in the access token).

Marking guidelines

  • 2 points for correct answer and access token VS body justification

Question 10 (3p)

Question

Describe the parts a JWT consists of. Then also explain why JWTs are secure to use (why a hacker can't fool a server by changing the data in the token or by creating her own token).

Marking guidelines

  • 0.25 points for each (somewhat) correct name
  • 0.50 points for each correct explanation
    • only 0.25 points if explanation lacks details or contains errors, but to some degree is correct
  • 0.75 points for explaining why they are secure

Question 11 (1p)

Question

When adding login functionality to a REST API, explain why it's usually not enough for the server to only send back an Access Token, but the server also needs to send back an ID Token.

Sample answer

When a user logs in, the client usually need to know information about the account the user logged in to, such as the account's id. Without that information, it would for example be impossible for the client to send requests and display information about resources belonging to that account, since the client can't identify the account.

Access Token are not designed to tell this information to the client, since they are only meant to be used for authorization. When implementing Access Tokens as JWT, it's possible for client to open up the Access Token and read information from it, but it's not something the client should rely on. For example, in the future, the server might change how it implements Access Token, so they are no longer implemented as JWT, and then the client code will no longer work.

So, instead, server usually send back an ID Token with the explicit purpose to contain information about the account the user logged in to, and is intended to be opened by the clients.

Marking guidelines

  • 1 point for correct explanation

Question 12 (1p)

Question

Does an ID Token has to be implemented as a JWT? Justify your answer

Sample answer

Yes, the specification for OpenID Connectopen in new window states:

The ID Token is represented as a JSON Web Token (JWT).

Marking guidelines

  • 1 point for correct answer and valid justification

Question 13 (1p)

Question

If client-side JS code on a webpage tries to send an HTTP DELETE request, will that always trigger a CORS pre-flight request? Justify your answer.

Sample answer

No, not always, not, for example, if the DELETE request is sent to the server as the origin of the client-side JS, because then it's not a Cross-site request, and the Same-Origin Policy won't stop the request from being sent to begin with, so CORS is not needed.

Marking guidelines

  • 1 point for correct answer and valid justification

Docker

Question 14 (1p)

Question

Explain what port mapping in Docker is, and give a practical example of when you need to use it.

Sample answer

All containers in Docker are running in an isolated environment, so no application on the host computer can communicate with an application in the container. By using port mapping, you can tell Docker that one port on the host computer should lead to one port in the container, and then the host computer can use this to communicate with an app in the container.

This is for example used when the container runs a web application, and you want to be able to send HTTP requests to it from a web browser running on the host computer.

Marking guidelines

  • 0.5 points for what it is
  • 0.5 points for practical example

Question 15 (1p)

Question

Explain what the Docker instruction COPY can be used for, and explain when that instruction is executed.

Sample answer

As all Docker instructions, the COPY instruction is executed when you build a Docker image. It instructs Docker to copy a file on the file system on the host computer to the file system that will exists in the container running the image.

Marking guidelines

  • 0.5 points for what the instruction does
  • 0.5 points for when it is executed

Scaling

Question 16 (1p)

Question

Explain how horizontal scaling works.

Sample answer

When a web application runs on a server and it receives more HTTP requests than it has time to handle, you can scale the application horizontally. That means you run the application on multiple servers behind a server that act as a load balancer. All clients send their HTTP requests to the load balancer, and the load balancer then forwards and distributes the HTTP requests among the servers running the web application, which carryout out the requests they receive and send back responses to the clients.

Marking guidelines

  • 0.5 points for application running on multiple servers
  • 0.25 points for explaining that the workload in distributed among the server
  • 0.25 points for explaining how the workload is distributed (load balancer)

JavaScript

Question 17 (2p)

Question

The function getAccountByUsername() should receive the username of an account as an argument, and it returns a promise that resolves to a JS object with information about the account with that username. If the account object can't be retrieved, the promise is rejected to a JS error object containing information about what went wrong.

The function getBlogpostsByAccount() should receive an account object as an argument, and it returns a promise that resolves to a JS array with objects representing blogposts that account has created. If the blogposts can't be retrieved, the promise is rejected to a JS error object containing information about what went wrong.

Implement the function getAccountWithBlogpostsByUsername(), that receives the username of an account as argument, and returns a promise that resolves to the account object with that username that also contains the property blogposts that stores an array with all the blogposts created by that account.

If you get an error from getAccountByUsername() or getBlogpostsByAccount(), then your own promise should be rejected with the string "getDataError".

It is OK to use async and await in your implementation.

Sample answer

async function getAccountWithBlogpostsByUsername(username){
	
	try {
		
		const account = await getAccountByUsername(username)
		account.blogposts = await getBlogpostsByAccount(account)
		return account
		
	}catch(error){
		
		throw "getDataError"
		
	}
	
}

Marking guidelines

  • 2 points for a solution that is largely correct
  • Point deductions for errors:
    • -0.25 points for returning {account, blogposts}
    • -0.25 points for retuning error instead of throwing
    • -0.25 points for not using "getDataError" as the rejected value