1.
Define REST API and di erentiate it from GraphQL
REST (Representational State Transfer) is an architectural style used to design networked
applications. It organizes interactions around resources, which are identified using URLs, and
uses standard HTTP methods to perform operations on those resources.
REST is stateless—each request must contain all necessary information, and the server doesn’t
store client context between requests.
Example: Getting a user's data using REST
What is GraphQL?
GraphQL is a query language for APIs and a runtime for fulfilling those queries. Unlike REST, it uses
a single endpoint and allows clients to specify exactly what data they need, reducing over-
fetching and under-fetching.
Example: Getting the same user data using GraphQL
Single Endpoint Request:
Response:
Key Di erences (with Context)
Feature REST API GraphQL
Endpoints Multiple: /users, /users/:id/orders Single: /graphql
Data Fetching May require multiple requests Single query fetches related nested data
Returns fixed structures (all
Over-fetching Returns only requested fields
fields)
Versioning Needs URL versioning (e.g., /v1/) Evolving schema avoids versioning
Data No strict schema; client must Strongly typed schema with
Types/Schema infer introspection
2. Explain how introspection and schema
documentation tools like GraphiQL enhance
development productivity in GraphQL.
GraphQL o ers a powerful feature called introspection, which allows clients to query the API for
details about its schema—such as types, fields, and operations (queries and mutations). This self-
awareness enables tools like GraphiQL, GraphQL Playground, and Apollo Studio Explorer to
provide interactive, real-time documentation and testing environments that significantly boost
developer productivity.
Key Benefits
1. Self-Documenting APIs
GraphQL schemas are inherently self-documenting. With introspection, tools can automatically
fetch and display:
Available queries and mutations
Input arguments and return types
Descriptions and deprecation notices (if defined in schema)
Example Introspection Query:
Sample Response:
2. Schema Exploration
Tools like GraphiQL and GraphQL Playground o er sidebar explorers, autocomplete, and type
tooltips—making it easy for developers to understand the structure, relationships, and
capabilities of the API without reading a manual.
3. Interactive Query Testing
Developers can compose, run, and debug queries and mutations in real time:
No need for separate Postman setups or frontend code
Syntax highlighting, auto-suggestions, and inline error feedback streamline testing
Example Usage in GraphiQL:
4. Always Up-to-Date Documentation
Because introspection reflects the current schema, tools built on it always display the latest API
structure—no more syncing separate documentation when the API changes.
3. Di erentiate between List API and Create API
integration with suitable examples.
1. List API Integration (Read Operation)
Purpose:
To fetch and display data (e.g., a list of issues) from the GraphQL server and render it in the UI.
Key Actions:
Define a GraphQL query
Use fetch() to send the query to the server
Update the UI with the retrieved data
Remove hardcoded/static data
Example Code (JavaScript with React):
Outcome:
Fetches a list of issues
Populates the component’s state
Automatically re-renders the UI
2. Create API Integration (Write Operation)
Purpose:
To add a new issue to the database by sending a GraphQL mutation, then refresh the list from the
server.
Key Actions:
Capture user input
Construct a GraphQL mutation
Use fetch() to send the mutation along with variables
Call loadData() again to refresh the list
Example Code (JavaScript with React):
Example Input:
Outcome:
Sends a mutation to add a new issue
Data is persisted on the server (e.g., in MongoDB)
The UI reloads the updated issue list from the server
Summary Table
Feature List API Create API
Operation Type Query (Read) Mutation (Write)
Feature List API Create API
Use Case Display existing issues Add a new issue
GraphQL Example query { issueList { id title ... } } mutation AddIssue($issue: IssueInputs!)
Input Required? No Yes (user input for new issue)
Response Set state with
Call loadData() to reload updated list
Handling result.data.issueList
Writes data to DB and fetches updated
Persistence Reads data from DB
state
4. Compare and contrast REST API and GraphQL in
terms of performance, data fetching e iciency, and
developer experience
1. Performance & Data Fetching E iciency
Feature REST API GraphQL
Common—returns full resource objects, Avoided—client specifies exactly
Over-fetching
even if the client needs only part which fields are needed
Requires multiple endpoints to retrieve Solved—can fetch deeply nested
Under-fetching
related data related data in a single query
Example To get a user and their issues: /users/1 + One query: { user(id: 1) { name,
Scenario /users/1/issues issues { id, title } } }
Network Smaller payloads and single
Higher payloads and round-trips
E iciency request for complex objects
Mobile More e icient—only needed data
Less e icient—more data transfer
Optimization transferred
Verdict:
GraphQL outperforms REST when minimizing data transfer and reducing the number of requests
needed, especially for nested or related data.
2. Developer Experience
Feature REST API GraphQL
Multiple per resource: /users,
Endpoints Single endpoint: /graphql
/issues, /issues/:id/comments, etc.
No built-in discoverability; requires Self-documenting via introspection;
Schema
documentation (Swagger, Postman, tools like GraphQL Playground or Apollo
Discoverability
etc.) Studio enable schema browsing
Limited by backend-defined Highly flexible—clients shape their
Query Flexibility
endpoints queries based on needs
Error structure varies across
Error Handling Unified and descriptive error format
endpoints
Strong IDE support, autocompletion,
Tooling Support Varies depending on the ecosystem
and query validation via schema
Typing & Weak typing unless combined with Strongly typed schema enforces
Validation external tools contract between client and server
Verdict:
GraphQL o ers a superior developer experience due to its schema introspection, flexibility,
and robust tooling, especially for front-end and full-stack developers.
Summary Table
Aspect REST API GraphQL
Data Fetching Over/under-fetching common Fetches exactly what is needed
Number of Multiple for nested/related
Single request for deeply nested data
Requests resources
Payload Size Often large (fixed fields) Minimal (custom fields)
Endpoints Multiple endpoints Single endpoint
Documentation External tools needed Self-documented schema
Aspect REST API GraphQL
Query Flexibility Defined by backend Defined by client
Tooling Support Depends on API ecosystem Excellent (GraphQL Playground, Apollo, etc.)
Higher (requires learning query syntax and
Learning Curve Lower (familiar HTTP verbs)
schema types)
5. Illustrate how to use MongoDB query language to
filter documents based on nested fields and array
values.
MongoDB stores data in BSON format (a binary representation of JSON), allowing documents to
contain nested objects and arrays. This flexible schema design enables rich and hierarchical
data models.
Sample Document (Invoice Collection)
In this document:
billingAddress is a nested object
items is an array of embedded objects
Querying Nested Fields
To query a nested field, MongoDB uses dot notation to reach into the structure.
Example 1: Filter by Nested Field (billingAddress.city)
Goal: Find all invoices where the billing city is New York.
Example 2: Filter by Nested Field with Operator
Goal: Find invoices where the billing ZIP code is greater than 10000.
Note: ZIP codes are typically stored as strings, so string comparison rules apply unless you
convert them to numbers.
Querying Arrays of Values and Objects
Example 3: Filter by Array Element Value
Goal: Find invoices that include Widget A in their items.
This works because MongoDB automatically checks each object in the items array for a match on
description.
Querying with Multiple Conditions in Array Objects
Example 4: Match Specific Conditions Within an Array Element
Goal: Find invoices with an item where:
description is "Widget B"
and price is greater than 40
$elemMatch ensures that both conditions apply to the same object within the array.
Filtering Based on Array Length or Exact Match
Example 5: Find Invoices with Exactly Two Items
6. Explain the MongoDB aggregation pipeline with
syntax and examples. Include at least two stages.
What is the MongoDB Aggregation Pipeline?
The MongoDB aggregation pipeline is a powerful data processing framework used to transform,
filter, analyze, and reshape data in a collection. It is conceptually similar to Unix pipelines and
SQL's GROUP BY, WHERE, and SELECT, but much more flexible.
Core Syntax
Each stage is an operation (represented as a document) that transforms the data. The output of
one stage becomes the input for the next.
Key Stages with Syntax and Examples
1. $match Stage — Filtering Data
Purpose:
Filters documents based on specific conditions, like WHERE in SQL. It's best placed early in the
pipeline to reduce processing cost.
Syntax:
Example:
Find employees whose age is greater than 30.
This filters the documents so that only those with age > 30 proceed to the next stage.
2. $group Stage — Aggregating Data
Purpose:
Groups documents by a field and performs aggregation like sum, average, min, max, count, etc.
Syntax:
Example A: Sum of All Ages
Group all documents together (_id: null) and sum their age values.
Example B: Average Age by Organization
Group by the organization field and compute the average age.
Combining $match and $group
You can chain $match and $group to first filter and then aggregate the result set.
Example C: Average Age of Employees Over 30, Grouped by Organization
7. Describe the role of documents, collections, and
databases in MongoDB. How do they relate to each
other?
In MongoDB, data is organized using a three-tier hierarchy: Databases → Collections →
Documents. Each level serves a distinct role and contributes to MongoDB's flexible, scalable, and
schema-less architecture. Here's a detailed explanation of each component and how they relate:
1. Documents
Role:
The document is the fundamental unit of data in MongoDB.
Structure:
o Stored in a BSON (Binary JSON) format.
o Consists of field-value pairs (like JSON objects).
o Fields can hold:
Primitive types: strings, numbers, booleans, dates, etc.
Embedded documents: objects within objects.
Arrays: lists of values or even other documents.
Example:
"_id": ObjectId("65f1a2b8c1f3d6"),
"name": "Alice",
"age": 28,
"address": {
"city": "Bangalore",
"zip": "560001"
},
"hobbies": ["reading", "cycling"]
Key Features:
o Every document must have a unique _id field.
o Provides flexibility — documents in the same collection can have di erent fields or
structures.
o Embedded data means faster reads — often no need for joins.
2. Collections
Role:
A collection is a group of related documents, similar to a table in relational databases.
Characteristics:
o No schema enforcement by default (i.e., schema-less).
o Optional schema validation can be added to enforce structure.
o You can create indexes on any field to improve performance, including those inside
embedded documents or arrays.
Example:
A collection called users might contain multiple documents like:
{ "name": "Alice", "age": 28 }
{ "name": "Bob", "email": "bob@example.com" }
Flexibility:
o Unlike SQL tables, documents in a collection don't need to have the same set of
fields or types.
o Collections are dynamically created upon first insert.
3. Databases
Role:
A database is a logical container for one or more collections.
Behavior:
o Similar to a database in SQL, but without foreign keys or enforced relationships.
o Mainly used for namespace separation (e.g., separate databases for di erent
applications or environments).
o A MongoDB instance can host multiple databases.
Commands:
o List databases:
show dbs
o Switch to a database (or create one on the fly):
use ecommerce
Isolation:
o Collections in di erent databases are isolated from each other.
o You typically operate within a single database per connection.
8. Compare and contrast reading and writing data to
MongoDB using the native Node.js driver versus
Mongoose.
When working with MongoDB in a Node.js application, you have two primary options:
1. MongoDB Native Node.js Driver – A low-level, direct interface to the database.
2. Mongoose – An Object Document Mapper (ODM) that adds structure and abstraction on
top of the native driver.
Here's a detailed comparison and contrast of both, based on the provided information and
expanded with practical insights:
1. MongoDB Native Node.js Driver
Description
O icial driver maintained by the MongoDB team.
O ers direct access to MongoDB operations with minimal abstraction.
Requires manual control over schemas, validation, and relationships.
Reading Data
const client = new MongoClient(uri);
await client.connect();
const db = client.db("shop");
const products = await db.collection("products").find({ category: "books" }).toArray();
Writing Data
await db.collection("products").insertOne({
name: "Node.js Guide",
price: 20,
category: "books"
});
Advantages
Fine-grained control: You interact directly with collections and documents.
Lightweight: No extra layers or abstraction.
Good for learning MongoDB fundamentals.
Disadvantages
No schema enforcement (unless you add your own validation logic).
More boilerplate for tasks like relationships, hooks, and validations.
Less intuitive for complex applications.
2. Mongoose (ODM)
Description
A high-level ODM (Object Data Mapper) for MongoDB.
Adds schema, models, validation, and middleware.
Ideal for applications where structure, relationships, and data consistency are important.
Reading Data
const Product = mongoose.model("Product", productSchema);
const books = await Product.find({ category: "books" });
Writing Data
const newProduct = new Product({
name: "Node.js Guide",
price: 20,
category: "books"
});
await newProduct.save();
Advantages
Schema enforcement: Define and validate document structure up front.
Built-in utilities: Relationships (populate()), hooks (pre, post), and validation.
Cleaner syntax: Especially helpful for large apps.
Disadvantages
More abstraction: You may not see how MongoDB really works under the hood.
Performance overhead: Slightly heavier due to features like casting and validation.
Less flexible: Sometimes gets in the way of custom MongoDB features (like aggregations)
9. Explain the process of integrating a List API with a
front-end React component.
Integrating a List API—such as a GraphQL endpoint—into a front-end React component (like
IssueList) transforms a static UI into a dynamic, data-driven one. Here's a step-by-step breakdown
based on your summary, with explanations and code-style examples for clarity:
1. Establish the Goal
You want the IssueList React component to fetch live data from a GraphQL List API, replacing any
hardcoded or in-memory array of issues.
2. Modify the loadData() Method
This method is responsible for fetching issues from the server. Initially, it may just return static
data:
loadData() {
this.setState({ issues: initialIssues });
Replace it with a method that fetches from the API.
3. Construct the GraphQL Query
Define the query to request specific fields from the API. Use a template literal:
const query = `
query {
issueList {
id title status owner
created e ort due
`;
4. Make the API Request Using fetch()
Use fetch() with POST to call the GraphQL endpoint, e.g., /graphql.
async function graphQLFetch(query, variables = {}) {
try {
const response = await fetch('/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables }),
});
const body = await response.json();
if (body.errors) {
alert(`GraphQL error: ${body.errors[0].message}`);
return body.data;
} catch (e) {
alert(`Network error: ${e.message}`);
return null;
5. Handle the API Response
Call graphQLFetch() inside loadData() and handle the returned data:
async loadData() {
const query = `...`; // Same as above
const data = await graphQLFetch(query);
if (data) {
this.setState({ issues: data.issueList });
6. Update Component State
You use this.setState() to update React state so that the component re-renders:
this.setState({ issues: data.issueList });
Never modify this.state directly—always use setState().
7. Handle Data Type Di erences
If dates are returned as ISO strings, format them accordingly:
<td>{new Date(issue.created).toDateString()}</td>
Or convert them earlier when setting state.
8. Trigger Data Fetching in componentDidMount()
Use React lifecycle method componentDidMount() to trigger the first data load:
componentDidMount() {
this.loadData();
This ensures the API request is made after the component is mounted.
9. Remove Hardcoded Data
Once live API data works, remove any:
const initialIssues = [ /* hardcoded array */ ];
This prevents outdated or duplicate rendering.
10. Implement Error Handling
Use try-catch around your fetch logic and check for errors in the API response:
if (body.errors) {
// show a UI error, alert, or fallback message
11. Verify Integration
After completing these steps:
Reload the browser
You should see data fetched from the live backend
Changes in the DB (e.g., new issues) should reflect automatically after refresh
Example Recap: Full loadData() with Integration
And in componentDidMount():
10. Describe introspection in GraphQL and its utility in
schema exploration.
What is Introspection in GraphQL?
Introspection refers to the ability to:
Query meta-information about the schema (types, fields, arguments, queries, mutations,
etc.)
Use special system fields like __schema, __type, __typename, etc.
Example Introspection Query:
This query returns a list of all types in the schema and details about the root query and mutation
types.
Utility in Schema Exploration
Introspection plays a critical role in development workflows:
1. Self-Documentation
Developers can understand available operations (queries/mutations/subscriptions)
without needing external docs.
Enables dynamic UI generation (e.g., dropdowns for queryable fields).
2. GraphQL IDE Support
Tools like:
GraphiQL
Apollo Sandbox / Apollo Studio
Insomnia
Postman (GraphQL mode)
...rely on introspection to:
Auto-complete fields
Show field descriptions and types
O er interactive schema explorers
3. API Exploration Without Backend Knowledge
Frontend devs can explore APIs without needing backend hand-holding.
Easily check what data is available, what arguments are accepted, and what types are
returned.
4. Tooling and Codegen
Tools like graphql-codegen, Apollo Codegen, and Relay Compiler use introspection results
to:
o Generate type-safe client code
o Create documentation
o Validate queries statically
Security Consideration
In production, some servers disable introspection to avoid exposing internal API
structures to attackers.
o Tools like graphql-shield can allow it in dev but restrict it in prod.
11. Explain the CRUD operations in MongoDB with
syntax and examples.
1. Create – Insert Documents
➤ insertOne(): Insert a single document
Syntax:
db.employees.insertOne({ id: 1, name: { first: 'John', last: 'Doe' }, age: 44 });
Node.js Example (async/await):
const result = await db.collection('employees').insertOne({ id: 1, name: { first: 'John', last: 'Doe' },
age: 44 });
console.log(result.insertedId);
➤ insertMany(): Insert multiple documents
Syntax:
db.employees.insertMany([
{ id: 2, name: { first: 'Jane', last: 'Doe' }, age: 30 },
{ id: 3, name: { first: 'Mark', last: 'Smith' }, age: 35 }
]);
In applications like issue trackers, you often generate custom unique IDs using a counter
collection with findOneAndUpdate() before calling insertOne().
2. Read – Retrieve Documents
➤ findOne(): Get a single document
Syntax: db.employees.findOne({ id: 1 });
➤ find(): Get multiple documents
Syntax: db.employees.find({ age: { $gte: 30 } });
Node.js Example:
const issues = await db.collection('issues').find({}).toArray();
console.log(issues);
➤ Common Filter Operators:
{ age: { $gte: 30 } } → age ≥ 30
{ name: "John" } → exact match
{ invoiceNumber: { $gt: 1000 } } → invoiceNumber > 1000
In the issueList() API function, find({}).toArray() is used to fetch all issues from the MongoDB
database.
3. Update – Modify Documents
➤ updateOne(): Update a single matching document
Syntax: db.employees.updateOne({ id: 1 }, { $set: { age: 45 } });
➤ updateMany(): Update all matching documents
Syntax: db.employees.updateMany({}, { $set: { organization: 'MyCompany' } });
➤ replaceOne(): Replace an entire document
Syntax: db.employees.replaceOne({ id: 1 }, { id: 1, name: 'Updated Name', age: 50 });
$set is used to update only specific fields rather than replacing the whole document.
4. Delete – Remove Documents
➤ deleteOne(): Delete the first matching document
Syntax: db.employees.deleteOne({ id: 4 });
➤ deleteMany(): Delete all matching documents
Syntax: db.employees.deleteMany({ age: { $lt: 20 } });
➤ Clear all documents from a collection
db.employees.remove({});
12. Develop a Node.js program that performs all CRUD
operations on a MongoDB collection named students.
13. Develop a Create API in GraphQL that accepts an
object with custom scalar types, validates the input,
and returns appropriate errors if any.
1. Schema (schema.graphql)
2. Custom Scalar Implementation (graphql_date.js)
3. Mutation Resolver (resolvers.js)
4. Apollo Server Setup (server.js)
5. Example Mutation Query (client-side, with variables)
14. Write a sample schema for a GraphQL About API
including custom scalar types.
Here's a sample GraphQL schema for an About API including the definition of a custom scalar
type GraphQLDate. Although the About API itself only uses basic types (like String), the schema
also declares a custom scalar for dates to demonstrate how you can include it for use elsewhere
in your application:
Explanation:
about: String! — Query to fetch the about message, guaranteed to return a string.
setAboutMessage(message: String!): String — Mutation to update the about message;
accepts a mandatory message and returns the updated string.
scalar GraphQLDate — Declaration of a custom scalar type for date handling. You will
implement this scalar’s behavior (parsing, serialization, validation) in your server resolvers.
This schema forms a simple About API while showing how to declare a custom scalar type in the
same schema file for future use.
15. What is a Graph-Based API? How does GraphQL
di er from traditional REST in terms of data
representation?
A Graph-Based API is an API that models and exposes data as a graph structure—where entities
(nodes) are interconnected through relationships (edges). This approach naturally represents
complex data and their interdependencies, allowing clients to query across related entities
seamlessly.
GraphQL is the most prominent example of a graph-based API. Instead of multiple endpoints
representing separate resources, GraphQL o ers a single endpoint where clients request exactly
the data they need, traversing relationships in a graph-like manner.
How does GraphQL di er from traditional REST in terms of data representation?
Aspect REST GraphQL
Graph-based: data as interconnected
Data Resource-based: distinct, self-contained
nodes and edges, representing objects
Model resources (e.g., /users, /orders).
and their relationships.
Multiple endpoints, each representing a Single endpoint (e.g., /graphql) serving
Endpoints
resource or action. all queries and mutations.
Aspect REST GraphQL
Often results in over-fetching (getting
Client specifies exactly which fields and
Data unnecessary data) or under-fetching
related data to fetch in one request—no
Fetching (requiring multiple requests to get related
over- or under-fetching.
data).
Less flexible, tied to predefined endpoints Highly flexible queries shaped by the
Flexibility
and payloads. client at runtime.
What is Introspection in GraphQL and its utility?
Introspection is a built-in feature of GraphQL servers that allows clients to query the API about its
own schema, types, fields, and operations.
Utility:
Enables self-documenting APIs—clients can discover what queries, mutations, and types
are available dynamically.
Powers developer tools like Apollo Playground or GraphiQL, providing interactive
exploration, autocompletion, and testing of API queries.
Removes the dependency on separate, often outdated, external documentation.
Facilitates rapid development by allowing developers to understand and adapt to API
changes quickly.
Introspection (Self-Documenting APIs)
GraphQL servers can describe their own schema dynamically.
o Developers can explore available queries and mutations without external
documentation.
o Tools like Apollo Playground allow real-time API exploration and testing.
Libraries
o Parsing and dealing with the type system language (also called the GraphQL
Schema Language) as well as the query language is hard to do on your own.
o Fortunately, there are tools and libraries available in most languages for this
purpose.
For JavaScript on the back-end, there is a reference implementation of GraphQL
called GraphQL.js. To tie this to Express and enable HTTP requests to be the
transport mechanism for the API calls, there is a package called express-
graphql.
But these are very basic tools that lack some advanced support such as
modularized schemas and seamless handling of custom scalar types.
The package graphql-tools and the related apollo-server are built on top of
GraphQL.js to add these advanced features. We will be using the advanced
packages for the Issue Tracker application in this chapter.
I will cover only those features of GraphQL that are needed for the purpose of the
application.
For advanced features that you may need in your own specific application, do
refer to the complete documentation of GraphQL at https://graphql.org and the
tools at https://www.apollographql.com/ docs/graphql-tools/.