Case studies and Mini Project on Web App Development
Chapter 8
Front-End Development and Full-Stack Integration
Diploma in Full Stack Programming
Case studies and Mini Project on Web App Development
•
Diploma
Front-End Development and Full-Stack Integration
Introduction
A modern web application is not merely a collection of pages. It is an interactive software system in which the browser presents information, collects user input, maintains temporary interface state, communicates with one or more services, and responds to changing data. Full-stack integration connects this front end to application programming interfaces (APIs), authentication services, databases, file storage, and operational monitoring.
This chapter examines the practical foundations of front-end development for a diploma-level full-stack programmer. Examples use contemporary component-based concepts and React-style syntax because these ideas are transferable to other frameworks such as Angular, Vue, Svelte, and similar tools. The emphasis is not on memorising one framework, but on understanding reusable components, controlled forms, state, routing, asynchronous operations, sessions, error handling, accessibility, and responsive design.
Learning Objectives
After completing this chapter, a learner should be able to:
Explain component-based front-end architecture and identify suitable component boundaries.
Build reusable UI components and controlled forms.
Distinguish local, shared, server, and URL state.
Implement routing and protected application areas.
Manage asynchronous requests, loading states, errors, and cancellation.
Integrate a front end with a REST-style API securely and consistently.
Handle authentication sessions without exposing sensitive credentials unnecessarily.
Apply responsive, accessible, and maintainable interface practices.
Analyse a full-stack case and justify design decisions.
1. The Front End as a System
The front end is the client-side part of an application. It runs primarily in a browser and performs four related responsibilities:
Presentation: rendering text, controls, images, and feedback.
Interaction: responding to clicks, typing, selection, and navigation.
State coordination: representing what the user sees and what the user has entered.
Communication: exchanging data with servers through HTTP or other protocols.
A useful conceptual model is:
Front end and back end integration flow
Figure: Front end and back end integration flow
Figure: A browser communicates with server resources through an API layer.
The front end should not contain business rules that belong exclusively to the server. For example, a browser may display whether a password appears valid, but the server must enforce password policy because browser code can be modified or bypassed.
2. Component-Based Architecture
A component is a cohesive unit of interface behaviour and presentation. It receives inputs, commonly called props, and produces a visual result. Components may be:
Presentational: primarily responsible for visual output, such as Button, Card, or Alert.
Container or feature components: coordinate state and operations, such as TaskList or CheckoutPage.
Layout components: define page structure, such as AppShell, Header, and Sidebar.
Route components: represent navigable screens.
A good component normally has one clear responsibility. Excessively large components are difficult to test and reuse; excessively small components can obscure the application structure. A practical boundary is a unit that has its own meaningful data, behaviour, accessibility concern, or reuse potential.
Props, composition, and state
Props flow from a parent to a child. A child should not silently mutate a prop. If a child needs to request a change, it calls a callback supplied by the parent. This unidirectional data flow makes changes easier to trace.
This example demonstrates composition: SavePanel supplies content and behaviour to a reusable button rather than duplicating button markup.
Component design principles
Cohesion: related markup and behaviour belong together.
Explicit interfaces: props should have understandable names and predictable types.
Low coupling: a button should not know how a database works.
Accessibility by default: semantic HTML and keyboard behaviour should be built into reusable controls.
Stable rendering: list items require stable keys based on identity, not array position when items can be reordered.
3. Forms and Validation
Forms are a principal boundary between the user and the system. A controlled input receives its value from application state and reports changes through an event handler. This permits immediate validation, consistent formatting, and reliable submission.
function LoginForm({ onSubmit }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
function submit(event) {
event.preventDefault();
if (!email.includes('@') || password.length < 8) {
setError('Enter a valid email and a password of at least 8 characters.');
return;
}
setError('');
onSubmit({ email, password });
}
return (
<form onSubmit={submit} noValidate>
<label htmlFor="email">Email address</label>
<input id="email" type="email" value={email}
onChange={event => setEmail(event.target.value)} required />
<label htmlFor="password">Password</label>
<input id="password" type="password" value={password}
onChange={event => setPassword(event.target.value)} required />
{error && <p role="alert">{error}</p>}
<button type="submit">Sign in</button>
</form>
);
}
Client-side validation improves user experience; it does not replace server-side validation. The server must validate type, length, allowed values, authorisation, and business rules. Validation messages should identify the correction without revealing sensitive information.
A robust submission process usually follows this sequence:
Prevent the browser’s default submission when using an asynchronous request.
Validate required fields and formats locally.
Disable duplicate submission while the request is active.
Send a well-formed request to the server.
Interpret success and failure responses.
Display field-level or general feedback.
Restore an actionable state after completion.
4. State Management
State is information that can change and influence rendering. It is useful to classify state before choosing a management technique.
State category
Example
Suitable location
Local UI state
Modal open, input text
Component state
Shared client state
Theme, current user summary
Context or state store
Server state
Tasks fetched from an API
Query/cache layer or feature state
URL state
Search term, page number, filter
Route parameters or query string
Persistent state
Language preference
Browser storage, subject to privacy considerations
State should be kept as close as possible to the components that use it. Lift it to a common parent only when siblings need coordinated access. Avoid storing values that can be derived from other state; duplicated state can become inconsistent.
State transitions
A state machine perspective is useful for asynchronous features. A request commonly has states such as idle, loading, success, and error. The interface should define valid transitions rather than relying on scattered Boolean flags such as isLoading, hasError, and isComplete, which may accidentally contradict each other.
A reducer is particularly useful when several events update related fields. Shared state libraries can provide caching, devtools, persistence, and predictable updates, but they should not be introduced merely because an application has more than one component.
5. Routing and Navigation
Routing maps a URL to a view. A single-page application may change the displayed component without a complete document reload, while still preserving meaningful URLs. Routes should represent user-understandable resources, for example:
/tasks — collection of tasks
/tasks/42 — task with identifier 42
/settings/profile — profile settings
Route parameters identify resources; query parameters commonly represent filtering, sorting, or pagination. Navigation should use the framework’s routing mechanism so browser history, back/forward actions, and deep links work correctly.
Protected routes require more than hiding a link. A front end may redirect an unauthenticated user to /login, but the server must also check authorisation on every protected request. A typical guard is conceptually:
function ProtectedRoute({ user, children }) {
if (user === undefined) return <LoadingIndicator />;
if (user === null) return <Navigate to="/login" replace />;
return children;
}
The undefined state distinguishes “authentication is still being checked” from “the user is known to be signed out.” Without this distinction, an application can redirect users prematurely during startup.
6. Asynchronous Data and API Integration
HTTP communication is asynchronous because the browser must wait for network, server, and database operations. A request should be modelled as a complete lifecycle, not simply as a call that returns data.
async function fetchTasks(signal) {
const response = await fetch('/api/tasks', {
method: 'GET',
credentials: 'include',
headers: { Accept: 'application/json' },
signal
});
if (!response.ok) {
let message = 'Unable to load tasks.';
try {
const body = await response.json();
message = body.message || message;
} catch (_) { /* retain general message */ }
throw new Error(message);
}
return response.json();
}
Important integration practices include:
Check the HTTP status; fetch does not reject merely because a server returns 404 or 500.
Set Content-Type: application/json when sending JSON.
Encode query parameters rather than concatenating untrusted text into URLs.
Use an AbortController when a component may unmount or a newer request supersedes an older one.
Treat response data as untrusted input and validate its shape.
Centralise common concerns such as base URLs, authentication handling, and error translation.
A typical request sequence is idle → loading → success or idle → loading → error. Empty results are not necessarily errors: an empty task list should normally receive an informative empty-state message.
Race conditions and stale responses
Suppose a user changes a search term quickly. Request A for “web” may finish after request B for “web app.” If A overwrites B, the interface displays stale data. Solutions include cancellation, request identifiers, or a data-fetching library that tracks query identity. The interface should show the result corresponding to the latest valid input.
API contracts
A contract defines request methods, paths, parameters, authentication requirements, response shapes, status codes, and error formats. Consistent contracts reduce front-end branching. For example:
Operation
Method and path
Success
Typical failure
List tasks
GET /api/tasks
200 with array
401, 500
Create task
POST /api/tasks
201 with object
400, 401
Update task
PATCH /api/tasks/:id
200 with object
400, 404, 403
Delete task
DELETE /api/tasks/:id
204
401, 403, 404
The front end should not infer success solely from a message string. Status codes and documented response schemas are more reliable.
7. Sessions and Security
Authentication establishes identity; authorisation determines what that identity may do. A session can be represented by a server-managed cookie or by a token-based mechanism. Security decisions belong to the whole system, not only the interface.
Cookie-based sessions
With a secure, HTTP-only session cookie, the browser sends the cookie automatically while client-side JavaScript cannot read it. Appropriate cookie attributes commonly include Secure, HttpOnly, and an intentional SameSite policy. Cross-site request forgery (CSRF) protections may still be required depending on the deployment and cookie configuration.
Token-based sessions
Access tokens may be sent in an Authorization header. Long-lived tokens in browser storage increase the impact of cross-site scripting (XSS), so storage, expiry, rotation, and refresh mechanisms require careful design. Never place passwords, private keys, or unrestricted secrets in front-end source code; anything shipped to the browser can be inspected.
Other essential controls include:
output escaping and safe rendering to reduce XSS;
HTTPS in production;
server-side authorisation checks;
rate limiting and account lockout policies where appropriate;
careful handling of personal data and logs;
clear logout and session-expiry behaviour;
dependency updates and vulnerability scanning.
8. Responsive and Accessible Interfaces
Responsive design adapts layout and interaction to available space and input method. Prefer fluid layouts, flexible grids, readable typography, and content-based breakpoints rather than designing only for named devices.
Accessibility is a functional requirement. Use semantic elements such as button, nav, main, label, and headings in logical order. Every form control needs an associated label. Keyboard focus must remain visible, and dynamic messages should be announced appropriately, often with role="status" or role="alert". Colour must not be the only means of communicating status, and contrast should support users with low vision.
Responsive behaviour also includes network and performance considerations: lazy-load noncritical resources, optimise images, avoid unnecessary re-renders, and provide useful feedback on slow connections. Performance should be measured with realistic devices and networks rather than assumed from a developer workstation.
9. Illustrative Case Study: Campus Task Board
This is a fictional illustrative case.
Background and problem
A college wants a task board where learners can create tasks, assign due dates, filter by status, and mark work complete. The initial prototype consists of one large page, duplicated buttons, local mock data, and no handling for session expiry. Users report that filters reset unexpectedly, duplicate submissions occur, and mobile users cannot comfortably edit tasks.
Analysis
The requirements reveal several state categories:
modal visibility and form fields are local UI state;
the signed-in learner is shared session state;
tasks are server state;
status and search filters belong in the URL so filtered views can be bookmarked;
an optimistic completion action requires rollback if the server rejects the update.
The application also requires a documented API contract and server-side ownership checks. A learner must not update another learner’s private task simply by changing an identifier in the browser.
Approach and solution
The team decomposes the interface into AppShell, TaskToolbar, TaskList, TaskCard, TaskForm, StatusMessage, and route-level pages. TaskCard receives a task and callbacks rather than making database assumptions. A query layer caches the task list by filter values and cancels obsolete searches.
The task form uses controlled inputs and displays field-level errors returned by the API. On submission, the save button enters a loading state. A successful 201 response adds the server-created object to the displayed list; a validation error preserves the user’s input. A general network failure provides a retry action rather than silently discarding data.
The application uses a protected route for the board, but the API independently verifies the session and task ownership. Session expiry produces a clear message and redirects to login only after the failed response has been interpreted. Filters are represented as URL query parameters, for example ?status=open&search=database.
Outcome
The revised design eliminates duplicated controls, supports keyboard navigation, behaves predictably on narrow screens, and prevents stale search results. The team also gains reusable request states and a consistent error format. Testing covers component rendering, form validation, route protection, API failures, and an end-to-end workflow from login through task creation.
Learning points
Component boundaries should reflect responsibility and reuse.
URL state is valuable when a view must be shareable or restorable.
Client validation improves experience, but server validation enforces trust.
Loading, empty, error, and success states are all part of the feature.
Security cannot be achieved by interface controls alone.
10. Testing and Professional Workflow
A professional front end is developed incrementally. Unit tests can verify pure functions such as reducers and validators. Component tests can check visible behaviour, keyboard interaction, and accessible labels. Integration tests can exercise a component with a realistic API boundary. End-to-end tests can verify critical journeys such as signing in, creating a record, and signing out.
Mocking should be selective. A mock that simply returns the expected answer may conceal incorrect request methods, headers, or error handling. Contract tests or schema validation help ensure that front end and back end evolve together.
A practical workflow is:
Define user stories and acceptance criteria.
Sketch states, routes, and API contracts.
Build semantic static components.
Add local state and form behaviour.
Integrate the API and model failure states.
Add authentication and authorisation assumptions.
Test keyboard, screen-reader, mobile, and slow-network behaviour.
Measure performance and review security before deployment.
11. Limitations and Contemporary Developments
Frameworks reduce repetitive work but introduce build systems, dependency risk, conventions, and upgrade costs. Server-side rendering and static generation can improve initial delivery and search indexing, but they introduce distinctions between server and browser execution. Progressive web application features can support installation and offline use, but offline synchronisation creates conflict and data-consistency problems that must be designed explicitly.
Artificial intelligence tools can assist with component scaffolding, test generation, accessibility checks, and API documentation. Generated code must be reviewed for insecure storage, missing authorisation, incorrect effect dependencies, licensing concerns, and inaccessible markup. AI does not remove the need to understand the application’s data model or security boundary.
Best-Practice Checklist
Use semantic HTML before adding ARIA.
Keep components cohesive and interfaces explicit.
Keep state close to its consumers and avoid duplicated derived state.
Model asynchronous operations with explicit lifecycle states.
Validate on both client and server.
Treat API responses and browser input as untrusted.
Protect routes in the UI and resources on the server.
Make loading, empty, error, and retry states visible.
Cancel or ignore obsolete asynchronous requests.
Test responsive, keyboard, accessibility, security, and failure behaviour.
Never expose secrets in client-delivered code.
Chapter Summary
Front-end development is the disciplined construction of an interactive client that presents information, captures input, manages state, navigates resources, and communicates with a server. Component-based design promotes reuse when components have cohesive responsibilities and explicit props. Forms require controlled input, useful validation, and reliable submission feedback. State should be classified as local, shared, server, URL, or persistent before a management technique is selected.
Routing gives application features meaningful URLs and supports navigation, while protected routes must be reinforced by server-side authorisation. Asynchronous integration requires explicit loading, success, empty, and error states; status checking, cancellation, and race-condition prevention are essential. Session design must consider cookies, tokens, XSS, CSRF, HTTPS, expiry, and least privilege. Responsive and accessible design are functional quality requirements. The Campus Task Board case demonstrates how these principles combine in a maintainable full-stack feature.
Key Terms
Component: A cohesive reusable unit of interface and behaviour.
Props: Inputs passed from a parent component to a child component.
State: Changeable data that influences rendering or behaviour.
Controlled input: A form control whose value is managed by application state.
Reducer: A function that calculates new state from current state and an action.
Routing: Mapping URLs and navigation actions to application views.
Route parameter: A variable segment of a resource URL.
Query parameter: URL data commonly used for filtering, searching, or pagination.
API: A defined interface through which software systems communicate.
HTTP status code: A server response code indicating the result category of a request.
Asynchronous operation: Work whose result becomes available later, such as a network request.
Race condition: Incorrect behaviour caused by results arriving in an unexpected order.
Authentication: Establishing the identity of a user or system.
Authorisation: Determining what an authenticated identity may access or change.
Session: Information representing an authenticated interaction over time.
CSRF: An attack that causes an authenticated browser to submit an unintended request.
XSS: Injection of executable script into content viewed by another user.
Responsive design: Interface design that adapts to different viewport sizes and contexts.
Accessibility: Designing software usable by people with varied abilities and assistive technologies.
Optimistic update: Showing an anticipated change before server confirmation, with rollback on failure.
Review Questions
Short Answer Questions
What is the difference between a component’s props and its state?
Why must server-side validation be performed even when a form validates input in the browser?
What is the purpose of an API contract?
Distinguish authentication from authorisation.
Name four lifecycle states that an asynchronous request may have.
Long Answer Questions
Explain how component composition and unidirectional data flow contribute to maintainability.
Describe a complete form-submission lifecycle, including validation, loading, success, and failure.
Compare local UI state, server state, and URL state, giving an example of each.
Explain the security considerations of cookie-based and token-based sessions.
Discuss how responsive design and accessibility should influence component development.
Analytical / Application Questions
A search page sends a new API request on every keystroke, but older results sometimes replace newer results. Analyse the cause and propose two technically sound solutions.
Design the component, route, state, and API structure for an authenticated student profile editor. Identify which responsibilities belong to the browser and which must remain on the server.
A task-completion button changes immediately, but the server rejects the update because the session expired. Design the user experience and state transitions needed to recover without misleading the user.
Multiple Choice Questions with Answers
Question 1
Which responsibility must be enforced by the server even if the front end hides an unauthorised button?
A. Button colour
B. Authorisation
C. Responsive layout
D. Keyboard focus styling
Correct Answer: B. Authorisation
Question 2
What is the primary advantage of controlled form inputs?
A. They remove the need for server validation
B. They allow the browser to bypass HTTP
C. Their values are coordinated with application state
D. They automatically encrypt passwords
Correct Answer: C. Their values are coordinated with application state
Question 3
Which state is most naturally represented in a URL query string?
A. Whether a modal is open
B. A search filter
C. The current CSS transition
D. A database connection
Correct Answer: B. A search filter
Question 4
What does fetch normally do when the server returns HTTP 404?
A. It always rejects the promise automatically
B. It converts the response into valid JSON
C. It resolves with a response whose ok property is false
D. It retries indefinitely
Correct Answer: C. It resolves with a response whose ok property is false
Question 5
Which practice helps prevent an older search response from overwriting a newer result?
A. Ignoring all response data
B. Cancelling obsolete requests
C. Removing the search input
D. Disabling browser history
Correct Answer: B. Cancelling obsolete requests
Question 6
Which cookie attribute prevents ordinary client-side JavaScript from reading the cookie?
A. HttpOnly
B. Public
C. Cacheable
D. Visible
Correct Answer: A. HttpOnly
Question 7
What is the main purpose of a reducer?
A. To define CSS breakpoints
B. To calculate new state from state and an action
C. To replace server-side authorisation
D. To compress images
Correct Answer: B. To calculate new state from state and an action
Question 8
Which response most appropriately represents successful creation of a resource in the case study API?
A. 201
B. 301
C. 401
D. 503
Correct Answer: A. 201
Question 9
Why is an empty result different from a network error?
A. An empty result can be a valid successful response
B. An empty result always indicates a server crash
C. A network error always means the user is unauthorised
D. They require identical interface messages
Correct Answer: A. An empty result can be a valid successful response
Question 10
Which HTML choice best supports accessible form development?
A. Using a placeholder as the only label
B. Using a clickable div instead of a button
C. Associating a label element with each form control
D. Communicating errors only through colour
Correct Answer: C. Associating a label element with each form control
Case studies and Mini Project on Web App Development
Chapter 8
of 15