Microsoft .NET Developer Interview Questions & Answers

microsoft icon

Questions with Detailed ExplanationsWith Detailed Explanations

(Last Updated: August 28, 2026)

11. Merge a New Interval.CodingEasyMicrosoft

Question Details

Insert one interval into a non-overlapping interval list and preserve order, explaining how to absorb overlaps on either side and where the new interval is placed if there is no collision.

Short Interview Answer (30-60 seconds)

I would use one linear pass through the sorted, non-overlapping intervals. I first copy intervals that finish before the new interval starts. Then I merge every interval whose start is less than or equal to the new interval's end by expanding the new start and end. I add that merged interval once, then append the remaining intervals. This preserves sorted order and removes overlaps. The time complexity is O(n), and the auxiliary space is O(1) excluding the output list.

Detailed Explanation

See the Code while reading this explanation.

We have a list of intervals that is already sorted and has no overlaps. We also have one new interval. We need to put the new interval into the correct place. If it touches or overlaps existing intervals, we combine them into one larger interval. The final list must stay sorted and must not contain overlaps. The diagram uses [[1,3], [6,9], [12,16]] with new interval [2,8]. The new interval merges with [1,3] and [6,9], so the final result is [[1,9], [12,16]].

Useful Questions to Ask the Interviewer
  1. Can I assume the existing intervals are already sorted by start value and do not overlap?
  2. Should touching intervals be treated as overlapping?
  3. Is it acceptable to update the new interval while I merge overlaps?
Merge a New Interval. diagram
How to Explain It in an Interview
1. Understand the input and required output

The input is a sorted list of non-overlapping intervals and one new interval. Each interval has a start and an end. The output is another sorted list with no overlaps. If the new interval does not overlap anything, it is placed in its sorted position. If it overlaps one or more intervals, all of those intervals are replaced by one merged interval.

2. Choose the algorithm and maintain the main invariant

Use one forward pass with an index and a result list. The key invariant is that every interval already placed in the result is completely before the current new interval and cannot overlap it. Because the original list is sorted, once we finish merging overlaps, every interval that remains must come after the merged interval.

3. Add intervals that come completely before the new interval

Start with index 0 and an empty result list. While the current interval ends before the new interval starts, copy it to the result. For the example, the first interval is [1,3] and the new interval is [2,8]. The test is 3 < 2, which is false, so nothing is copied before the merge phase.

4. Merge every overlapping interval

Now process intervals while the current start is less than or equal to the new interval's end. At index 0, [1,3] overlaps [2,8]. Update the new interval to [min(2,1), max(8,3)] = [1,8]. At index 1, [6,9] overlaps [1,8]. Update it to [min(1,6), max(8,9)] = [1,9]. At index 2, [12,16] starts at 12, and 12 <= 9 is false, so merging stops.

5. Add the merged interval and append the rest

Add [1,9] to the result exactly once. The current index is now 2. Append every remaining interval starting from that position. We append [12,16]. The final result becomes [[1,9], [12,16]].

6. Explain why the result is correct

Intervals copied before the merge phase end before the new interval begins, so they cannot overlap it. During the merge phase, the new interval is expanded to cover the full union of every overlapping interval. When the merge loop stops, the next interval starts after the merged interval ends. Because the original list is sorted and non-overlapping, all later intervals also come after it. Therefore the output stays sorted and non-overlapping.

7. Explain complexity and edge cases

Each existing interval is visited at most once, so the running time is O(n), where n is the number of existing intervals. The algorithm uses only an index and the interval being merged, so auxiliary space is O(1) when the required output list is excluded. Important cases are an empty input, insertion before all intervals, insertion after all intervals, overlapping several intervals, the new interval being contained inside an existing interval, and touching intervals such as end == start, which the diagram treats as overlapping.

Key Insight / Why This Solution Works

The key idea is to use the sorted order to divide the work into three consecutive parts. First, copy intervals that are completely before the new interval. Second, absorb every interval that overlaps the new interval by setting the merged start to the smaller start and the merged end to the larger end. Third, add the merged interval once and copy everything that remains. The central invariant is that every interval already copied to the result is completely before the current merged interval and can never overlap it. Because the input is sorted, no interval needs to be revisited.

Code
using System;
using System.Collections.Generic;

public sealed class Interval
{
    public int Start;
    public int End;

    public Interval(int start, int end)
    {
        Start = start;
        End = end;
    }
}

public static class Program
{
    public static IList<Interval> Insert(IList<Interval> intervals, Interval newInterval)
    {
        // Store the final sorted, non-overlapping intervals.
        List<Interval> result = new List<Interval>();
        int i = 0;
        int n = intervals.Count;

        // Copy every interval that finishes before the new interval starts.
        // These intervals cannot overlap the new interval.
        while (i < n && intervals[i].End < newInterval.Start)
        {
            result.Add(intervals[i]);
            i++;
        }

        // Merge every interval that starts before or exactly when the
        // current merged interval ends. Touching intervals are merged.
        while (i < n && intervals[i].Start <= newInterval.End)
        {
            // Expand the new interval so it covers the full overlap.
            newInterval.Start = Math.Min(newInterval.Start, intervals[i].Start);
            newInterval.End = Math.Max(newInterval.End, intervals[i].End);
            i++;
        }

        // Add the fully merged interval exactly once.
        result.Add(newInterval);

        // All remaining intervals start after the merged interval ends,
        // so append them in their existing sorted order.
        while (i < n)
        {
            result.Add(intervals[i]);
            i++;
        }

        return result;
    }

    public static void Main()
    {
        // Run the exact example shown in the diagram.
        List<Interval> intervals =
            new List<Interval> { new Interval(1, 3), new Interval(6, 9), new Interval(12, 16) };
        Interval newInterval = new Interval(2, 8);

        IList<Interval> merged = Insert(intervals, newInterval);

        // Print the result as [[1,9], [12,16]].
        Console.Write("[");
        for (int i = 0; i < merged.Count; i++)
        {
            if (i > 0)
            {
                Console.Write(", ");
            }

            Console.Write($"[{merged[i].Start},{merged[i].End}]");
        }
        Console.WriteLine("]");
    }
}
Time & Space Complexity

Let n be the number of existing intervals. The time complexity is O(n) because the index only moves forward and each interval is processed at most once. The algorithm does not create a second working array, map, stack, or queue. Apart from the required result list, it keeps only the index and the interval being expanded. Therefore the auxiliary space is O(1) excluding the output list. The output itself can contain O(n) intervals.

Where it is used

This pattern is useful when software stores sorted time ranges or numeric ranges and must insert a new range while combining conflicts. Examples include calendar time blocks, booking windows, maintenance periods, reserved resource ranges, and ranges of data that should be kept ordered without overlaps.

Why Interviewers Ask This

This problem tests whether you recognize that sorted intervals let you solve the task with one forward pass. The interviewer can see whether you choose the correct overlap conditions, maintain a clear invariant, merge both left and right boundaries correctly, and preserve sorted order without unnecessary sorting. It also tests whether your C# implementation matches your explanation and whether you can state O(n) time and O(1) auxiliary space excluding the required output accurately.

Common interview mistakes

A common mistake is adding the new interval before all of its overlaps have been absorbed. Another is using the wrong overlap test and missing touching intervals when end == start. Candidates may also forget to update both the start and end when an overlap extends to the left or right. Another mistake is restarting a scan or sorting again even though the input is already ordered. Finally, the stated O(1) auxiliary space excludes the result list, so claiming total memory including the output is O(1) would be inaccurate.

Interview tip

Explain the solution as three ordered phases: copy intervals before the new one, merge all overlaps into the new one, then append the rest. While coding, keep the two key comparisons visible: current.End < new.Start for the left side and current.Start <= new.End for overlap.

Interviewer may ask next
What changes if touching intervals should stay separate instead of being merged?

Both boundary comparisons must change. In the first loop, use current.End <= newInterval.Start so an interval that ends exactly where the new interval starts is copied before it instead of merged. In the merge loop, use current.Start < newInterval.End so an interval that starts exactly where the merged interval ends stays separate. The same three-phase structure and invariant still work. Time remains O(n), and auxiliary space remains O(1) excluding the output.

What happens if the new interval does not overlap any existing interval?

The algorithm does not need a different method. The first loop copies every interval that ends before the new interval starts. The merge loop executes zero times because the next interval starts after the new interval ends. The algorithm then adds the new interval once and appends the remaining intervals. This places the new interval in the correct sorted position. The time complexity remains O(n), and the auxiliary space remains O(1) excluding the output.

12. Buildings with an Ocean View.CodingMediumMicrosoft

Question Details

Return the buildings with an unobstructed ocean view from one side of the skyline, and describe how you decide visibility while scanning the array once.

Short Interview Answer (30-60 seconds)

I would scan the buildings from right to left, starting from the ocean side. I keep the tallest height seen so far in maxHeight. If the current building is taller than maxHeight, then every building to its right is strictly shorter, so I save its index and update maxHeight. I reverse the saved indices at the end to restore left-to-right order. This takes O(n) time, uses O(1) auxiliary space, and uses O(k) space for the returned indices.

Detailed Explanation

See the Code while reading this explanation.

We have an array of building heights. The ocean is on the right side. We must return the indices of buildings that can see the ocean. A building can see the ocean only when every building to its right is strictly shorter. The useful idea is to start from the ocean side and move left. We remember the tallest building already seen on the right. This lets us decide each building's visibility immediately instead of comparing it with every building after it.

Useful Questions to Ask the Interviewer
  1. Can I assume the ocean is on the right side, as shown in the example?
  2. Should I return the visible building indices in their original left-to-right order?
Buildings with an Ocean View. diagram
How to Explain It in an Interview
1. Understand the input and required output

The input is an integer array named heights. Each array position is a building index, and the value at that position is the building height. We return indices, not heights. The diagram example is heights = [4, 2, 3, 1, 5, 1, 2, 4]. The correct result is [4, 7]. Building 4 has height 5, and building 7 has height 4.

2. Choose the scanning direction

The ocean is on the right, so I scan from right to left. I keep one value called maxHeight. It represents the tallest building already seen to the right. The main rule is simple: if heights[i] > maxHeight, then building i can see the ocean.

3. Initialize the state

I start with an empty result list. Conceptually, maxHeight starts at negative infinity because no building has been seen yet. In the C# implementation, I use a long initialized to long.MinValue so every possible int building height, including int.MinValue, is handled correctly. I begin at index 7 and move toward index 0.

4. Walk through the example

At index 7, the height is 4. Since 4 is greater than the starting maxHeight, I add index 7 and set maxHeight to 4. At index 6, height 2 is not greater than 4, so I skip it. Index 5 has height 1, so I skip it. At index 4, height 5 is greater than 4. I add index 4 and update maxHeight to 5. Indices 3, 2, 1, and 0 have heights 1, 3, 2, and 4. None is greater than 5, so all are skipped. The result collected during the right-to-left scan is [7, 4]. I reverse it to get [4, 7].

5. Explain why the result is correct

Before processing index i, maxHeight is the tallest height among all buildings already processed to the right of i. Therefore, heights[i] > maxHeight means the current building is taller than every building to its right. That is exactly the condition for an unobstructed ocean view. When a building qualifies, I update maxHeight because it becomes the new tallest building seen from the right.

6. Explain the C# implementation

The code creates a List<int> for the result and scans from heights.Length - 1 down to 0. When heights[i] is greater than maxHeight, it stores index i and updates maxHeight. After the loop, it reverses the list because qualifying indices were discovered from right to left. The returned list therefore follows the original left-to-right index order.

7. Explain complexity and edge cases

The loop processes each building once, so the time complexity is O(n). Reversing at most k returned indices is O(k), and k is at most n, so the total remains O(n). The algorithm itself uses only a few variables, so auxiliary space is O(1). The returned list needs O(k) space. An empty array returns an empty list. A single building is visible. If all heights are equal, only index n - 1 is visible. For strictly increasing heights, only index n - 1 is visible. For strictly decreasing heights, every index is visible.

Key Insight / Why This Solution Works

The key insight is to scan from the ocean side. When scanning from right to left, we only need to remember the tallest building seen so far. The invariant is: before processing index i, maxHeight is the maximum height among all buildings to the right of i. If heights[i] > maxHeight, the current building is taller than every building to its right, so it has an ocean view. We add its index and update maxHeight. Otherwise, at least one building to its right is as tall or taller and blocks the view. This replaces repeated right-side comparisons with one running maximum.

Code
using System;
using System.Collections.Generic;

public static class Program
{
    public static void Main()
    {
        // Use the exact example shown in the diagram.
        int[] heights = { 4, 2, 3, 1, 5, 1, 2, 4 };

        // Find the indices of buildings with an unobstructed ocean view.
        IList<int> visibleBuildings = FindBuildings(heights);

        // Expected output for the diagram example: 4, 7
        Console.WriteLine(string.Join(", ", visibleBuildings));
    }

    public static IList<int> FindBuildings(int[] heights)
    {
        // Store visible building indices as they are found from right to left.
        List<int> result = new List<int>();

        // Use a value lower than every possible int height so the rightmost building qualifies.
        long maxHeight = long.MinValue;

        // Scan from the ocean side, which is the right side of the array.
        for (int i = heights.Length - 1; i >= 0; i--)
        {
            // A building is visible only when every building to its right is strictly shorter.
            if (heights[i] > maxHeight)
            {
                // Save the original index because the required output is a list of indices.
                result.Add(i);

                // This building is now the tallest building seen from the right.
                maxHeight = heights[i];
            }
        }

        // The scan found indices in right-to-left order, so restore left-to-right order.
        result.Reverse();

        // Return the visible building indices.
        return result;
    }
}
Time & Space Complexity

Time complexity is O(n). We visit each of the n buildings once during the right-to-left scan. Reversing the result takes O(k), where k is the number of visible buildings. Since k cannot be larger than n, the total time is still O(n). Auxiliary space is O(1) because the algorithm keeps only the loop index and maxHeight. The returned result list uses O(k) space to store the visible building indices.

Where it is used

This right-to-left running-maximum pattern is useful when an item must be compared with everything on one side, but only the largest value on that side matters. Similar scans can find suffix maximums, record-breaking values, or items that remain visible from one direction. It avoids repeatedly scanning the same suffix of an array.

Why Interviewers Ask This

This problem checks whether you can replace repeated comparisons with a simple running-state scan. The interviewer wants to see whether you choose the correct traversal direction, maintain the maxHeight invariant, distinguish indices from values, use the strict comparison correctly, and explain why one pass is enough. It also tests whether your C# implementation matches your reasoning and whether you can state O(n) time, O(1) auxiliary space, and O(k) returned-output space accurately.

Common interview mistakes

A common mistake is returning building heights instead of their indices. Another mistake is scanning left to right while using the same maxHeight rule, because that would track buildings on the wrong side. Using >= instead of > is also wrong because an equal-height building on the right blocks the view. Candidates may update maxHeight to a smaller height after a blocked building, which destroys the running-maximum invariant. Another common mistake is forgetting to reverse the collected indices, which would return [7, 4] instead of [4, 7].

Interview tip

State the invariant before coding: maxHeight is the tallest building already seen to the right. Then explain that heights[i] > maxHeight is exactly the ocean-view condition. This makes the traversal direction, strict comparison, state update, and final reversal easy to justify.

Interviewer may ask next
What changes if the ocean is on the left side instead of the right side?

I would reverse the traversal direction. I would scan from index 0 to n - 1 and keep the tallest height seen so far on the left. If heights[i] > maxHeight, I would add index i and update maxHeight. The invariant is still the same idea: maxHeight is the tallest building between the current building and the ocean. Because qualifying indices are discovered in left-to-right order, no final reverse is needed. Time remains O(n), auxiliary space remains O(1), and the returned result uses O(k) space.

What if the interviewer asks for the visible building heights instead of their indices?

The traversal and visibility condition stay the same. I would still scan from right to left and compare heights[i] with maxHeight. When a building is visible, I would add heights[i] to the result instead of i, then update maxHeight. I would still reverse the collected values at the end to restore left-to-right order. The same invariant proves correctness. Time remains O(n), auxiliary space remains O(1), and the returned values use O(k) space.

13. What is the time complexity of a linear search algorithm?CodingHardMicrosoft

Question Details

Answer the Microsoft MLE prompt with the precise asymptotic cost of linear search, including best-case, average-case, and worst-case behavior on an unsorted list.

Short Interview Answer (30-60 seconds)

I would use linear search because the list is unsorted. I start at index 0 and compare each value with the target from left to right. I process each item at most once and stop as soon as I find a match. The best case is Θ(1), the average case is Θ(n), and the worst case is Θ(n), which is also O(n). The algorithm only uses a few variables, so the auxiliary space is O(1).

Detailed Explanation

See the Code while reading this explanation.

The problem asks how the running time of linear search changes as an unsorted list becomes larger. We look for one target value by starting at the first element and checking values from left to right. If a value matches, we immediately return its index. If the list ends without a match, we return -1. This method fits an unsorted list because there is no ordering that lets us safely skip elements.

Useful Questions to Ask the Interviewer
  1. Should the search return the index of the first matching value when duplicates exist?
  2. Should we return -1 when the target is not present?
  3. For average-case analysis, should we assume the target is equally likely to be at any position?
What is the time complexity of a linear search algorithm? diagram
How to Explain It in an Interview
1. Understand the input and required output

The input is an unsorted integer array and a target integer. The output is the index of the first matching element. If no element matches, the method returns -1. In the diagram, the array is [23, 7, 15, 9, 31, 18] and the target is 31. The correct returned index is 4.

2. Choose linear search

Because the array is unsorted, we cannot use ordering to discard part of the input. Linear search checks values from left to right. The central invariant is that before checking index i, every earlier index has already been checked and did not contain the target. Therefore, when A[i] equals the target, i is the first matching index and can be returned immediately.

3. Initialize the search

Set i to 0. This starts the search at the first array element. No extra collection is needed. While i is less than the array length, compare A[i] with the target. If they are different, increase i by 1 and continue.

4. Walk through the example

Start with i = 0 and target = 31. At index 0, A[0] is 23. It is not 31, so move to index 1. At index 1, A[1] is 7. It is not 31, so continue. At index 2, A[2] is 15, so continue. At index 3, A[3] is 9, so continue. At index 4, A[4] is 31. The condition is true, so return index 4 immediately. Five comparisons were made. Index 5 is not processed because the algorithm has already returned.

5. Explain why the result is correct

The search examines elements in index order. Before each comparison, every earlier element has already been shown not to match the target. Therefore, the first equality found is the first matching position. If the loop finishes, every array element has been checked and none matched, so returning -1 is correct.

6. Explain the C# implementation

The method first rejects a null array. It stores the array length in n. A for loop visits indices from 0 through n - 1. At each index, it checks whether A[i] equals target. A match returns i immediately. If the loop completes without returning, the method returns -1. The executable example searches [23, 7, 15, 9, 31, 18] for 31 and returns 4. It also demonstrates that searching for 100 returns -1.

7. Explain complexity and edge cases

If the target is at index 0, only one comparison is needed, so the best case is Θ(1), also expressible as O(1) and Ω(1). If the target is equally likely to be at any position, the average number of comparisons is (n + 1) / 2, which is Θ(n). If the target is last or absent, n comparisons are needed, so the worst case is Θ(n), and therefore O(n). Auxiliary space is O(1). An empty array returns -1 and takes constant time. A one-element array needs one comparison. With duplicates, the first matching index is returned.

Key Insight / Why This Solution Works

The key idea is to search the unsorted array in its natural left-to-right order. No extra data structure is needed. At index i, compare A[i] with the target. Return i immediately when they are equal. Otherwise move to i + 1. The central invariant is that before index i is checked, every earlier index has already been checked and does not contain the target. This makes an early return correct and also guarantees that duplicates produce the first matching index. If the loop reaches the end, the target is not present.

Code
using System;

public static class Program
{
    public static int LinearSearch(int[] A, int target)
    {
        // Reject a null input because there is no array to search.
        if (A == null)
        {
            throw new ArgumentNullException(nameof(A));
        }

        // Store the number of elements so the loop has a clear stopping boundary.
        int n = A.Length;

        // Visit each element from left to right at most once.
        for (int i = 0; i < n; i++)
        {
            // Compare the current value with the target.
            // Stop immediately on a match, so this is also the first matching index.
            if (A[i] == target)
            {
                return i;
            }
        }

        // Reaching this point means every element was checked and no match was found.
        return -1;
    }

    public static void Main()
    {
        // Use the exact array from the diagram.
        int[] A = { 23, 7, 15, 9, 31, 18 };

        // Search for 31. The algorithm stops at index 4 after five comparisons.
        int index = LinearSearch(A, 31);
        Console.WriteLine(index); // 4

        // Demonstrate the diagram's not-found behavior.
        // The method checks all six elements before returning -1.
        int notFound = LinearSearch(A, 100);
        Console.WriteLine(notFound); // -1
    }
}
Time & Space Complexity

Let n be the number of elements. In the best case, the target is at index 0, so linear search makes 1 comparison. That is Θ(1), with O(1) and Ω(1) bounds. In the diagram's average case, the target is equally likely to be at any position, so the average number of comparisons is (n + 1) / 2. That grows linearly, so it is Θ(n). In the worst case, the target is last or absent, so all n elements are checked. That is Θ(n), and therefore O(n). We process the input at most once. The algorithm keeps only a few variables, so auxiliary space is O(1).

Where it is used

Linear search is useful when data is unsorted, the collection is small, or searches are infrequent enough that building another index or data structure is not worthwhile. It is also useful when items are processed in sequence and each item must be inspected until a match is found.

Why Interviewers Ask This

This question tests whether the candidate can distinguish best-case, average-case, and worst-case analysis instead of giving only one Big-O value. It also checks whether the candidate understands unsorted input, sequential traversal, and early return. In C#, the interviewer can see whether the candidate writes a simple loop correctly, returns the proper index, handles the not-found case, reasons about duplicates, and explains constant auxiliary space accurately.

Common interview mistakes

A common mistake is saying linear search is simply O(1) because it may stop early. That describes only the best case. Another mistake is saying the average case is constant. Under the diagram's equal-position assumption, the average case is Θ(n). Candidates may also continue scanning after finding the target instead of returning immediately. Another mistake is returning the matching value instead of its index. With duplicates, this left-to-right implementation should return the first matching index. It is also incorrect to claim that the algorithm uses O(n) extra memory because it stores only a few variables.

Interview tip

State the three cases separately: one comparison in the best case, about half the list on average under the equal-position assumption, and all n elements in the worst case. Then mention that the loop stops immediately on a match and uses O(1) auxiliary space.

Interviewer may ask next
What changes if the input array is already sorted?

Linear search is still correct and still uses O(1) auxiliary space, but sorted data allows binary search. If the required output remains the first matching index when duplicates exist, use a leftmost-occurrence version of binary search. It keeps searching the left half after finding a match. The worst-case time becomes O(log n) and the iterative auxiliary space remains O(1). The tradeoff is that binary search depends on the array being sorted.

What changes if duplicate values exist?

The algorithm does not need to change if the required result is the first matching index. It checks indices from left to right and returns immediately on the first equality, so it naturally returns the leftmost match. The best case remains Θ(1), the worst case remains Θ(n), and auxiliary space remains O(1). If every matching index were required instead, we could not return early. We would scan all n elements, giving Θ(n) time plus space for the returned indices.

14. Design Azure API Gateway for client requests that need routing, rate limiting, and authentication.API DesignEasyMicrosoft

Question Details

Describe how an API gateway should route requests, apply authentication, and enforce limits before traffic reaches the backend services.

Short Interview Answer (30-60 seconds)

At a high level, I would put Azure API Management in front of the backend services. Clients send HTTPS requests to the gateway. The gateway validates the caller, applies rate limits, routes the request to the correct backend, and runs shared policies such as logging or transformations. Microsoft Entra ID supports token validation. The backend returns its HTTPS response through the gateway to the client. The benefit is centralized security and traffic control. The trade-off is that the gateway adds another important dependency and policy layer to operate.

Detailed Explanation

The goal is to give clients one safe entry point before requests reach backend services. We want to check who is calling, stop one caller from sending too much traffic, and send each valid request to the correct service. The gateway also gives us one place to apply common rules and observe traffic. The diagram uses Azure API Management for this job. Requests can come from web, mobile, or third-party clients. They pass through the gateway, reach a selected backend service, and return through the same gateway.

Useful Questions to Ask the Interviewer
  • Are all clients expected to use Microsoft Entra ID tokens, or can some use API keys?
  • Should rate limits differ by subscription, user, or IP address?
  • Do different backend services need different routing or transformation policies?
Design Azure API Gateway for client requests that need routing, rate limiting, and authentication. diagram
How to Explain It in an Interview
1. Start with Azure API Management as the entry point

I would place Azure API Management between the clients and backend services. The web app, mobile app, and third-party applications send HTTPS API requests to the gateway. This creates one controlled entry point. The gateway owns the shared checks before traffic reaches a backend service. That keeps the behavior consistent across different kinds of clients.

2. Authenticate the caller first

The request first reaches the authentication stage. Azure API Management validates a JWT or OAuth2 access token. A JWT is a signed token that carries identity information. The diagram also shows an API key and mTLS as optional checks. Microsoft Entra ID is the identity system. It supports OAuth2 and OpenID Connect, issues tokens, and represents user or application identities. The gateway validates the token with Entra ID and receives the validation result. If authentication is invalid, the gateway rejects the request instead of forwarding it.

3. Apply rate limits before backend work

After authentication, the gateway applies rate limiting. Rate limiting means controlling how many requests a caller may send. The limit can be based on subscription, user, or IP address. The diagram also shows quotas and throttling. Azure API Management Cache stores counters and rate-limit state used by this flow. If a caller exceeds its allowed limit, the gateway rejects the request before backend resources are used.

4. Route the valid request

Next, the routing stage decides where the request should go. It can match the path, HTTP method, headers, or query values shown in the diagram. It then selects the correct backend service. The available backend examples are Azure App Service, Azure Functions, and Container Apps or AKS. The routing stage can also transform request headers or the request body when the configured rules require it.

5. Run gateway policies and forward the request

The policy execution stage applies shared gateway behavior. The diagram shows caching, request or response transformation, logging, and correlation or tracing. After these gateway policies run, Azure API Management forwards the API request to the selected backend over HTTPS. Azure Key Vault stores secrets, certificates, and API keys. API Management policies and products are reusable, while named values reference secrets and configuration.

6. Return the backend response through the gateway

The selected backend processes the request and sends an HTTPS response back to Azure API Management. The response then enters response handling. The gateway can apply response policies and transformations before returning the final HTTPS response to the original client. Request and response remain separate flows, and the response travels from the backend through the gateway back to the caller.

7. Observe the system and explain the trade-off

Azure Monitor and Application Insights receive logs, metrics, and traces from the gateway flow. They provide alerts, dashboards, and end-to-end visibility. Monitoring is a supporting path and does not own the business response. The benefit of the design is centralized authentication, limiting, routing, policy control, and observability. The trade-off is extra operational complexity. A gateway problem or incorrect shared policy can affect many services, so configuration and policies need careful management.

Practical Complexity & Trade-offs

The benefit of this design is that common API rules live in one place. Authentication, rate limiting, routing, logging, caching, and transformations do not need to be repeated in every backend. Rate limiting protects backend capacity before expensive work starts. Microsoft Entra ID provides the identity and token side of the design. Azure Key Vault keeps secrets, certificates, and API keys outside normal gateway configuration. The downside is that Azure API Management becomes an important dependency. More policies can also make request behavior harder to understand. Caching may improve performance, but cached information must remain correct for its intended lifetime. We accept this extra gateway complexity because it provides one controlled entry point and consistent traffic management.

Why Interviewers Ask This

Interviewers use this question to test whether you understand what an API gateway should own. They want to see a correct request and response flow, sensible authentication, rate limiting before backend work, and routing to the correct service. They also look for judgment about shared policies, secrets, logging, and operational trade-offs. A strong answer separates identity, traffic control, routing, backend processing, response handling, and observability clearly.

Interviewer may ask next
What would you do if traffic increased sharply and many clients started exceeding their limits?

I would keep the same architecture and use the rate-limiting stage as the main protection point. Azure API Management would still authenticate each request first. It would then apply the configured quota or throttling rule before routing traffic to a backend. The limits can remain based on subscription, user, or IP address, as shown in the diagram. Azure API Management Cache continues to store the counters and rate-limit state used by this flow. Requests that stay within the allowed limit continue through routing and policy execution normally. Requests that exceed the configured limit are rejected at the gateway, so Azure App Service, Azure Functions, or Container Apps and AKS do not spend capacity processing them. I would use Azure Monitor and Application Insights to watch request volume, rejected traffic, latency, and backend behavior. The downside is that stricter limits may reject legitimate traffic bursts, so the limits must balance protection with normal client demand.

How would you manage authentication secrets and certificates without putting them directly in API Management policies?

I would keep the request flow the same and use Azure Key Vault for the secrets, certificates, and API keys shown in the diagram. Azure API Management would still perform its authentication checks, including JWT or OAuth2 token validation and the optional API key or mTLS checks. The sensitive values would remain in Key Vault instead of being copied directly into ordinary policy configuration. API Management named values can reference secrets and configuration, while policies and products remain reusable. Microsoft Entra ID continues to provide OAuth2 or OpenID Connect identity and token functionality. After authentication succeeds, the request still moves through rate limiting, routing, policy execution, and then to the selected backend. The response returns through the same gateway path. The benefit is safer secret handling. The downside is extra work around permissions, certificate updates, and secret references. Incorrect secret configuration can cause authentication or policy execution to fail.

15. Design a public contract for data aggregation across Azure tenants when requests are rate limited.API DesignEasyMicrosoft

Question Details

Define the request and response shape for tenant data aggregation, including how callers learn about throttling and retry guidance.

Short Interview Answer (30-60 seconds)

At a high level, I would expose one public aggregation endpoint that accepts a query, tenant IDs, metrics, a time range, aggregation level, and paging data. The caller sends HTTPS POST /v1/aggregations with a bearer access token. The Aggregation API validates the JWT and scopes, applies caller and tenant quotas, fans out to Azure tenant data sources, and returns per-tenant results. Success returns 200. Throttling returns 429 with retry timing and quota details. The trade-off is stronger protection and fairness at the cost of client retry logic and possible partial results.

Detailed Explanation

This question asks us to design one public service that collects information from several Azure tenants. The caller should send one clear request and receive one clear result. The main challenge is that the service cannot accept unlimited traffic. It must tell callers when they have sent too many requests and when they should try again. The design also needs safe access, paging for larger result sets, and useful results when some tenants fail. I will follow the diagram from the caller, through the Aggregation API, to the tenant data sources, and back.

Useful Questions to Ask the Interviewer
  • Should one request be allowed to include many tenant IDs?
  • Are partial tenant failures acceptable in a successful response?
  • Should rate limits apply by caller, tenant, or both?
  • How large can one result page be?
Design a public contract for data aggregation across Azure tenants when requests are rate limited. diagram
How to Explain It in an Interview
1. Define the public request contract

I would start with HTTPS POST /v1/aggregations. The caller first acquires a token and sends the request with Content-Type: application/json and Authorization: Bearer {access_token}. The body contains query, tenantIds, metrics, timeRange, aggregationLevel, and page. The aggregation level can be tenant, subscription, or resource. The page object contains a size and an optional continuationToken. This makes the request explicit about the data, tenants, time range, and paging position.

2. Authenticate, authorize, and apply quotas

The Aggregation API owns authentication and authorization. It validates the JWT and required scopes before aggregation begins. It also applies rate limits using caller and tenant quotas. These limits protect the service and help keep usage fair. If the caller exceeds a limit, the API does not continue the normal aggregation flow. Instead, it returns the 429 Too Many Requests contract described later. Requests that fail identity or scope checks are rejected before downstream tenant calls occur.

3. Fan out to Azure tenant data sources

For an allowed request, Aggregation Orchestration fans out to Tenant A, Tenant B, through Tenant N. It collects and normalizes the returned data. The downstream tenant API calls use app identities or delegated permissions as configured. The reliability controls shown in the diagram include timeouts, retries to downstream services, and a circuit breaker. These controls help when a tenant data source is slow or temporarily unavailable while preserving the same public API contract.

4. Return the successful response and paging state

A successful aggregation returns JSON with status 200. The response contains requestId, generatedAt, timeRange, aggregationLevel, and a results array. Each tenant result contains a tenantId, a status, and metrics. The response can also contain partialFailure.failedTenants, so successful tenant data can still be returned when another tenant fails. Paging uses next.continuationToken and expiresInSeconds. The caller uses the continuation token to resume the next page rather than restarting the result sequence.

5. Make throttling and retry guidance explicit

When a rate limit is exceeded, the API returns 429 Too Many Requests. The response contains requestId and an error whose code is TooManyRequests. The throttling object tells the caller the affected scope, such as caller, tenant, or global. It also provides retryAfterSeconds, retryAfterUtc, limit, remaining, resetUtc, and a retry policy. The client waits for the supplied retry time and then retries with exponential backoff and jitter. This makes recovery behavior part of the public contract instead of forcing callers to guess.

6. Explain the cross-cutting decisions and trade-off

Security uses OAuth 2.0 with Microsoft Entra ID, JWTs, and least-privilege scopes. Observability uses requestId in responses, structured logs, and metrics. The API is versioned with v1 in the path and favors backward-compatible changes. The diagram also treats retrying the same request with the same token and page as safe. The main trade-off is extra contract and client complexity from quotas, paging, retries, and partial failures. In return, the API handles load more safely and gives callers clear recovery information.

Practical Complexity & Trade-offs

The benefit is a clear contract for both normal and throttled calls. POST /v1/aggregations keeps the query and tenant list in one request. JWT and scope checks protect access before fan-out begins. Per-caller and per-tenant quotas improve fairness, but clients must handle 429 correctly. Retry timing reduces guessing, while exponential backoff with jitter helps avoid retry spikes. Paging keeps large responses manageable, but continuation tokens add client state. Partial failures preserve useful tenant data, but clients must inspect each tenant status. Downstream timeouts, retries, and a circuit breaker improve reliability, while adding operational complexity. Versioning with v1 gives the contract a clear evolution path, and backward-compatible changes reduce disruption for existing callers.

Why Interviewers Ask This

Interviewers use this question to test whether you can turn an aggregation need into a clear public API contract. They want correct request and response modeling, proper 200 and 429 behavior, and useful retry guidance. They also check whether you separate authentication, authorization, rate limiting, fan-out, and response shaping. Strong answers show judgment about paging, partial failures, reliability, observability, versioning, and trade-offs without making unsupported guarantees.

Interviewer may ask next
What would you change if one Azure tenant is slow or fails during aggregation?

I would keep the same public endpoint and preserve successful tenant data while reporting the failed tenant clearly. The affected flow is the Aggregation Orchestration step behind POST /v1/aggregations. It already fans out to Tenant A through Tenant N, collects results, and normalizes them. For a slow or failing tenant, the service uses the shown downstream timeouts, retries, and circuit breaker. If other tenants succeed, the existing 200 response shape can still include their results and place the failed tenant under partialFailure.failedTenants with its tenant ID, error code, and message. The caller can then use the successful data without guessing which tenant failed. JWT validation, scope checks, caller and tenant quotas, paging, and the public request body remain unchanged. The main downside is that a 200 response does not necessarily mean every tenant succeeded. Clients must inspect each tenant status and the partial-failure information before treating the aggregation as fully complete.

How should a client behave when the Aggregation API returns 429?

The client should follow the throttling information returned by the Aggregation API instead of retrying immediately. The affected flow is the JSON response from POST /v1/aggregations back to the caller. A 429 Too Many Requests response includes requestId, the TooManyRequests error, and a throttling object. The client should read the scope, such as caller, tenant, or global, and wait for retryAfterSeconds or until retryAfterUtc. After that delay, it should retry using exponential backoff with jitter. It should also respect limit, remaining, and resetUtc so it does not create another request burst. If the caller is paging through results, it should use the existing continuationToken to resume the paged results. JWT and scope requirements remain unchanged on retries. The downside is more client logic and extra latency, but this behavior protects the service and makes rate-limit recovery predictable.

16. Design an API boundary for OneDrive file sync with delta updates and conflict reporting.API DesignMediumMicrosoft

Question Details

Focus on the file-sync API surface, including delta fetches, version tokens, and the error model for sync conflicts.

Short Interview Answer (30-60 seconds)

At a high level, I would put OneDrive file sync behind one clear API boundary. The client sends HTTPS requests with a JWT bearer token through the API Gateway. The gateway validates the JWT, routes traffic, logs requests and responses, and applies throttling. The ASP.NET Core sync service handles delta updates, version tokens, conflicts, and sync responses, then reads or writes OneDrive data through Microsoft Graph or Drive. Conflicts also follow an asynchronous reporting path. The trade-off is more components, but responsibilities stay clear and the stateless service can scale.

Detailed Explanation

This question asks us to design a simple way for OneDrive clients to keep files in sync. The client should learn what changed without reading every file again. It also needs to know which file version it is using. When two clients create conflicting changes, the system must make that conflict visible instead of hiding it. The design also needs a safe request path and a separate way to report conflicts. I will follow the diagram from the client, through the gateway and sync service, to OneDrive storage, then cover conflict reporting.

Useful Questions to Ask the Interviewer
  • Should Windows, web, and mobile clients all use the same sync boundary?
  • How quickly should users be notified about a conflict?
  • Should clients resolve conflicts interactively or only read conflict details?
Design an API boundary for OneDrive file sync with delta updates and conflict reporting. diagram
How to Explain It in an Interview
1. Start at the client and gateway

I would start with the OneDrive Client. It monitors local changes and sends an HTTPS request with a JWT bearer token to the API Gateway. HTTPS protects data while it moves across the network. The API Gateway is the reverse proxy. It validates the JWT, routes requests, records request and response logs, and applies throttling. Throttling limits excessive request rates before traffic reaches the sync service.

2. Route work to the sync service

After validation, the gateway sends the API request to the OneDrive Sync Service using HTTPS plus the JWT. It owns delta handling, conflict detection and resolution, version token management, and sync-response construction. The response returns in the opposite direction. The sync service returns JSON to the gateway. The gateway then returns JSON to the client.

3. Fetch only delta changes

The main delta endpoint is GET /drives/{driveId}/delta. It gets changes since the client's last token. The shown response contains changes plus nextLink. Inside the sync service, delta handling uses the SharePoint/Drive API shown in the diagram. OneDrive Storage contains files and metadata, a change log for delta processing, and version history. Version token management also helps the service track the sync position used by the client.

4. Upload files and read metadata

The diagram shows POST /drives/{driveId}/items for uploading or updating a file. Its response contains item metadata plus version information. It also shows GET /drives/{driveId}/items/{itemId} for reading item metadata. That response contains item metadata plus an eTag. An eTag is a version marker that helps the client recognize item state. For these operations, the sync service reads or writes OneDrive data through Microsoft Graph or Drive. Storage returns a JSON data response to the sync service.

5. Detect and expose conflicts

Conflict detection and resolution belong to the OneDrive Sync Service. The service can include conflicts when it builds the sync response. The diagram also exposes GET /sync/conflicts so a client can read pending conflicts. Its response contains conflict details. The diagram does not define a conflict status code or payload schema, so I would not invent either.

6. Report conflicts asynchronously

The sync service also sends a separate Report conflicts asynchronous event to Conflict Reporting, shown as an Event Hub or Queue. That component persists conflict details, supports notification, and enables the resolution workflow. Conflict Reporting then sends a Notify event to User Notification. That component can provide email or in-app conflict summaries, resolution options, and a path to continue sync. This side path does not block the normal request and response flow.

7. Close with scaling and trade-offs

The diagram describes the sync service as stateless, which makes horizontal scaling easier because requests do not depend on local session state. The trade-off is operational complexity. The gateway adds a network hop. Conflict reporting and notifications add more components. I would accept that cost because the design keeps sync traffic, conflict handling, and user notification clearly separated.

Practical Complexity & Trade-offs

The benefit is clear ownership. The gateway handles JWT validation, routing, logging, and throttling. The sync service handles delta work, version tokens, conflicts, and response building. Delta requests reduce work because clients fetch only changes since the previous sync position. Version information and eTags help clients reason about changing file state. The stateless service is easier to scale across multiple instances. The downside is more moving parts. The gateway adds another network hop. The Event Hub or Queue and notification component also need monitoring and operation. This is more complex than one large API, but the separation keeps normal sync requests independent from slower conflict reporting and user notification work.

Why Interviewers Ask This

Interviewers ask this to see whether you can draw a clean API boundary around a real synchronization problem. They want correct request and response directions, sensible endpoint choices, delta handling, version tracking, JWT validation, throttling, and clear conflict behavior. They also test ownership judgment: which component should route, sync, store, report, or notify. A strong answer explains the trade-offs clearly instead of only naming technologies.

Interviewer may ask next
How would this design behave if the number of sync clients increased sharply?

I would keep the same boundary and scale the stateless OneDrive Sync Service horizontally. The affected flow is the API request from the API Gateway to the sync service. Because the service does not depend on local session state, different requests can be handled by different service instances. The gateway continues to validate JWTs, route requests, log traffic, and apply throttling. Throttling becomes more important during a spike because it limits excessive traffic before it reaches the service. Delta requests also reduce load because clients ask only for changes since the last token instead of scanning every file. The storage flow through Microsoft Graph or Drive stays the same. Conflict reporting also remains asynchronous through the Event Hub or Queue, so notification work does not block the main response. The downside is higher operational cost. More service instances and more traffic require capacity planning and monitoring, while the gateway remains an important shared part of the request path.

What happens when two clients create conflicting changes to the same file?

The OneDrive Sync Service detects the conflict and keeps it visible to the client. The affected area is the service's conflict detection and resolution responsibility, together with version token management and item version information. The service can include conflicts when it builds the sync response, and the client can call GET /sync/conflicts to read pending conflict details. The diagram does not specify a conflict status code or exact error payload, so I would not invent one. Separately, the sync service sends a Report conflicts asynchronous event to the Conflict Reporting Event Hub or Queue. That component persists conflict details and supports the resolution workflow. It then sends a Notify event to User Notification, which can provide an email or in-app summary and resolution options. JWT validation, routing, logging, throttling, and the normal storage path remain unchanged. The downside is more conflict-handling logic, but the design avoids silently hiding competing changes.

17. Design an API boundary for Teams chat with message ordering and presence updates.API DesignMediumMicrosoft

Question Details

Describe the message-send, presence-read, and ordering guarantees that the client-facing chat API must expose.

Short Interview Answer (30-60 seconds)

At a high level, I would expose one client-facing Chat API for ordered messages and real-time presence updates. Clients send messages with POST /v1/chats/{chatId}/messages, read messages by sequence number, and subscribe to the presence stream. The boundary validates JWTs, authorization, tenant isolation, and rate limits. Messages receive a monotonically increasing sequence per chat, so clients display the same order. Presence is best-effort and eventually consistent. The trade-off is stronger coordination for message ordering, while presence stays lighter and more responsive.

Detailed Explanation

The goal is to make chat behave consistently on desktop, mobile, and web. A user should send a message, read messages in the same order later, and receive useful presence changes. The main challenge is that messages need strong ordering, while presence changes often and can tolerate small delays. The design puts one Chat API Boundary in front of ordering, durable message storage, and presence services. Clients only access this boundary. Internal services remain private.

Useful Questions to Ask the Interviewer
  • Is message ordering required only inside one chat, or across all chats?
  • Can presence information be briefly stale during network problems?
  • Should a reconnecting client continue from its last known message sequence?
Design an API boundary for Teams chat with message ordering and presence updates. diagram
How to Explain It in an Interview
1. Start with the client-facing API boundary

I would expose the public contract through the Chat API Boundary using .NET and ASP.NET Core. Teams Desktop, Teams Mobile, and Teams Web send HTTPS requests with a bearer JWT. The boundary handles JWT validation, scopes, authorization, tenant isolation, throttling, and rate limits before protected work continues.

Clients cannot directly access the Ordering Service, Message Store, or Presence Service. The diagram keeps those components behind the trust boundary. Internal service-to-service communication uses mTLS. Cross-cutting concerns include logging, telemetry, CorrelationId, audit information, and feature flags.

2. Send a message and assign its order

The send endpoint is POST /v1/chats/{chatId}/messages. The client sends the request over HTTPS with a JWT. The Chat API validates and authorizes the request. It assigns a GUID MessageId, persists and publishes the message flow, and works with the Ordering Service to obtain the message sequence.

The Ordering Service owns a per-chat sequencer. It generates a monotonically increasing Seq. This gives every committed message in one chat a stable position. The diagram shows MessageCreated information moving from the Chat API toward the Ordering Service and Seq Assigned (InitialSeq) returning to the API. The Ordering Service persists the ordered message data to the Message Store.

The client receives 202 Accepted with MessageId, ServerTimestamp, and InitialSeq.

3. Read messages using sequence-based paging

Clients read messages with GET /v1/chats/{chatId}/messages?fromSeq=X&limit=Y. The Chat API reads from the Message Store using chatId, fromSeq, and limit. The Message Store returns Messages[] in ascending sequence order.

The client receives 200 OK with Messages[] and NextSeq. Sequence-based paging is important because device clocks can disagree. A sequence number gives each message a stable position inside one chat. The guarantee is therefore a strict total order per chat, not one global order across all chats.

4. Explain delivery, idempotency, and read behavior

The ordering guarantees state that events are published in commit order and clients apply them by Seq. Delivery is at least once, so duplicate delivery can happen. Clients de-duplicate repeated events using eventId or sequence information.

The design also uses a client-generated ClientMsgId for idempotent sends. This means a retried send can have one logical effect instead of creating another message. The design does not claim exactly-once transport.

The sender has read-your-writes behavior. The sender receives the created-message event with its assigned sequence. Read receipts are per user and per message. Read state is monotonic, so once a message is read, it remains read.

5. Keep presence real-time but eventually consistent

Presence uses GET /v1/chats/{chatId}/presence/stream. The client opens the real-time connection using WSS with a JWT. The Chat API subscribes to presence events for the chat. The Presence Service aggregates user signals, computes user state, and publishes presence deltas.

Clients receive changes such as join, leave, idle, and offline. Presence is best-effort and eventually consistent. Clients receive ordered deltas per connection, but presence does not use the durable message-ordering guarantee. If a client is offline, it can use its last known state and re-sync after reconnecting.

6. Explain failures and the main trade-off

The diagram uses RFC 7807 Problem Details for API errors. Authentication, authorization, tenant isolation, validation, throttling, and rate-limit checks belong at the Chat API Boundary. The diagram only shows 202 Accepted for message send and 200 OK for message reads, so I would not invent additional response codes.

The main trade-off is deliberate. Messages use a per-chat sequencer because ordering is correctness-critical. This adds coordination to the write path. Presence changes much more frequently, so it uses a best-effort, eventually consistent model. That keeps presence responsive without weakening message ordering.

Practical Complexity & Trade-offs

The main design choice is to give messages stronger rules than presence. A per-chat sequence gives every message a clear position. The benefit is that desktop, mobile, and web clients can display the same order. The downside is extra coordination during message writes. Sequence-based paging is safer than paging by time because device clocks may differ. A client-generated ClientMsgId makes send retries idempotent, while event de-duplication handles at-least-once delivery. JWT validation, authorization, tenant isolation, throttling, and rate limits protect the public boundary. Internal services remain private and use mTLS. Presence accepts weaker consistency. This reduces coordination cost, but a presence value can briefly be stale.

Why Interviewers Ask This

Interviewers ask this question to test whether you can choose different guarantees for different product needs. They want clear API boundaries, correct request and response flows, and sensible message ordering. They also evaluate authentication, authorization, tenant isolation, rate limiting, idempotency, pagination, and real-time behavior. A strong answer explains why messages need durable per-chat ordering while presence can accept eventual consistency, without claiming stronger guarantees than the design provides.

Interviewer may ask next
What happens if a message event is delivered more than once or a client reconnects after missing updates?

I would keep the same API and recover using the sequence-based design already shown. Message delivery is at least once, so duplicate events are possible. The client de-duplicates repeated events using eventId or sequence information. If its connection drops, the client remembers its last processed sequence. After reconnecting, it calls GET /v1/chats/{chatId}/messages?fromSeq=X&limit=Y. The Chat API reads the missing range from the Message Store and returns messages in ascending Seq order with NextSeq. This preserves the same per-chat ordering without requiring exactly-once transport. The public security checks remain unchanged. JWT validation, authorization, tenant isolation, throttling, and rate limits still happen at the Chat API Boundary. The downside is that clients need a small amount of recovery state and de-duplication logic. We accept that complexity because it makes retries and reconnects safe without changing the ordering architecture.

Why does presence use weaker consistency than chat messages?

Presence changes frequently, so I would keep the best-effort and eventually consistent model shown in the design. The affected flow is GET /v1/chats/{chatId}/presence/stream and the Presence Service behind it. The Presence Service aggregates signals, computes user state, and publishes deltas such as join, leave, idle, and offline. Clients receive those updates through the WSS real-time connection. If a client disconnects, it can keep the last known state and re-sync after reconnecting. The security boundary stays the same. Clients authenticate to the Chat API using a JWT, while internal service-to-service communication remains private and uses mTLS. Message ordering is unchanged because presence does not use the per-chat message sequencer. The downside is temporary staleness. One client can briefly show an older presence value, but that avoids adding expensive ordering coordination to every presence change.

18. Design a public interface for a proximity service like Yelp or Nearby Friends.API DesignMediumMicrosoft

Question Details

Describe the request contract for nearby lookup, including location inputs, filtering criteria, and what the API returns to callers.

Short Interview Answer (30-60 seconds)

At a high level, I would expose one nearby-search API for mobile, web, and server clients. Clients call GET /v1/nearby over HTTPS with coordinates, radius, filters, and a bearer JWT. The API Gateway validates the JWT, applies rate limits, logs the request, and routes it to the .NET 8 proximity service. The service validates inputs, performs geospatial search, filtering, and ranking, then shapes a JSON response. A geo index and Redis improve lookup speed. The main trade-off is faster reads and better scale versus extra infrastructure and possible cache staleness.

Detailed Explanation

The problem is to let an application ask, "What useful places are near this location?" The caller gives us its position and may narrow the results by distance, category, rating, opening status, or language. We need a public interface that is easy to understand and gives predictable results. The harder part is making location searches fast while protecting the service from bad or excessive requests. I would follow the diagram from the client request, through the gateway and .NET service, into the data stores, and then back to the caller.

Useful Questions to Ask the Interviewer
  • Are we mainly returning businesses and places, or should nearby people also use this contract?
  • What maximum search radius should clients be allowed to request?
  • How fresh must place information and cached results be?
  • Should distance remain the default ranking, or should popularity or rating sometimes lead?
Design a public interface for a proximity service like Yelp or Nearby Friends. diagram
How to Explain It in an Interview
1. Define the public nearby endpoint

I would expose GET /v1/nearby. The required location inputs are lat and lon, using WGS84 coordinates. Optional inputs are radius, limit, offset, categories, open_now, min_rating, sort_by, include, language, and currency.

The shown radius range is 1 to 50000 meters. The shown limit range is 1 to 100. categories accepts comma-separated category IDs. open_now keeps only places currently open. min_rating filters by rating. sort_by can use distance, rating, or popularity. include can request details, photos, and reviews. language uses an ISO 639-1 value, and currency uses ISO 4217.

2. Send the request through the API Gateway

The client sends the request over HTTPS. The required Authorization header carries Bearer {access_token} as a JWT. Accept is application/json. An optional X-Request-Id lets the client provide an ID for tracing.

The API Gateway handles TLS 1.2+, JWT validation, rate limiting, request logging, and request routing. After those checks, it forwards the request to the Proximity Service through the internal HTTP/JSON flow shown in the diagram.

3. Process the lookup in the .NET service

The Proximity Service runs on .NET 8 with ASP.NET Core. Its Nearby Lookup Handler receives the forwarded request. The service validates the location and filtering inputs before searching.

It then performs filtering and ranking. The service also owns response shaping, which keeps the public JSON contract separate from internal storage details. Telemetry and logging record operational information without becoming part of the business response path.

4. Read from the data stores and indexes

The service queries the data layer and receives results back. The Places / Businesses DB can use SQL Server or PostgreSQL and stores places, categories, reviews, and metadata. The Geo Index can use Elasticsearch or PostGIS and supports fast geospatial radius queries. Redis caches popular queries and place details.

The diagram also shows optional Maps and Geocoding and an Identity Provider using OAuth 2.0 / OpenID Connect. These are supporting integrations. They are not shown as replacements for the main client-to-gateway-to-service request path.

5. Return the successful response

The Proximity Service returns results to the API Gateway. The gateway then returns an HTTPS 200 OK JSON response to the client.

The response contains request_id, the normalized query, a results array, paging, and meta. A result can contain place_id, name, distance_m, rating, review_count, categories, address, lat, lon, is_open, price_level, photos, and place_url. Pagination includes offset, limit, and next_offset. Results are ranked by proximity by default, with rating or popularity available as other sorting choices.

6. Explain failures and API behavior

The diagram shows 400 invalid_request for missing or invalid query parameters. 401 unauthorized means the authentication token is missing or invalid. 403 forbidden means the client is not allowed to access the resource. 429 rate_limited means the caller sent too many requests. 500 internal_error represents an unexpected server error.

The API uses HTTPS and OAuth2/JWT authentication. The GET operation is idempotent, meaning repeating the same lookup does not itself change server state. Timestamps use ISO 8601 in UTC. Clients should also respect rate-limit information communicated in response headers.

Practical Complexity & Trade-offs

The benefit of this design is a small public API with clear location and filtering inputs. The Geo Index makes radius searches much faster than scanning ordinary database rows. Redis can reduce repeated work for popular queries and place details. The downside is that cached information can become older than the main database, so freshness must be managed. The API Gateway centralizes TLS, JWT validation, rate limiting, logging, and routing. That keeps these concerns outside the main lookup logic, but it adds another component to run. Pagination with limit and offset keeps responses reasonably sized, although large offsets may become less efficient. Clear 400, 401, 403, 429, and 500 responses also make client behavior easier to implement and troubleshoot.

Why Interviewers Ask This

Interviewers ask this question to test whether you can turn a product idea into a clear public API contract. They want to see correct location inputs, filters, pagination, response modeling, and HTTP behavior. They also evaluate whether you place responsibilities correctly between the API Gateway, .NET service, geo index, database, and cache. Good answers show judgment around authentication, rate limiting, geospatial lookup, caching, error handling, scalability, and the trade-offs between speed, freshness, simplicity, and operational complexity.

Interviewer may ask next
How would this design handle a large increase in nearby-search traffic?

I would keep the public GET /v1/nearby contract unchanged and scale the existing lookup path. The API Gateway would continue validating JWTs, applying rate limits, logging requests, and routing valid traffic. The Proximity Service would keep the same validation, filtering, ranking, and response-shaping responsibilities.

For the search itself, I would rely on the existing Geo Index for radius queries instead of scanning the Places / Businesses DB. Redis would become more valuable for popular queries and frequently requested place details because cache hits avoid repeated backend work. The existing limit parameter also keeps individual responses bounded, with the diagram allowing values from 1 to 100.

Correctness stays the same because a cache miss still follows the normal lookup path and returns the same response contract. Security also remains unchanged because requests still pass through the gateway controls.

The main downside is cache freshness. More aggressive caching can reduce latency and backend load, but callers may briefly receive older place details. We accept that only within the product's agreed freshness requirement.

How should clients handle authentication, authorization, and rate-limit failures?

Clients should handle each shown HTTP failure according to its meaning. A 401 unauthorized response means the bearer token is missing or invalid, so the caller must correct its authentication before retrying. The API Gateway is the component shown validating the JWT.

A 403 forbidden response is different. It means the client is not allowed to access the resource. The diagram defines that public response, so the caller should not treat it as a malformed-token problem. A 429 rate_limited response means the client has exceeded the allowed request rate. The notes say clients should respect rate limits communicated in response headers.

The successful path stays unchanged. Valid requests still go from the client through the API Gateway to the .NET Proximity Service, then to the data stores and indexes, with results returning through the gateway as JSON.

The benefit of separate status codes is that clients know what kind of problem occurred. The downside is that client applications need distinct handling for authentication, access, and traffic-limit failures.

19. Design a message-delivery API for a WhatsApp-like system.API DesignHardMicrosoft

Question Details

Describe the client-facing message contract, including acknowledgements, offline delivery behavior, and how read receipts are surfaced.

Short Interview Answer (30-60 seconds)

At a high level, I would make message acceptance fast while keeping delivery reliable. The client sends POST /v1/messages with a bearer JWT through the API Gateway. The gateway handles authentication, rate limiting, validation, and routing to the .NET Messaging Service over HTTPS with mTLS. The service stores message state and places delivery work on a durable broker. Online users receive real-time WebSocket updates. Offline users are queued for later delivery and may receive push notifications. Separate acknowledgements show SENT, QUEUED, DELIVERED, and READ. The trade-off is more asynchronous state to manage.

Detailed Explanation

This question asks us to design how a chat app sends a message and tells both users what happened afterward. The sender should quickly know that the server accepted the message. The receiver may be online or offline. Online users should get messages quickly. Offline users should receive them later. The system must also show when a message reaches the receiver and when the receiver reads it. I will follow the diagram and use its client, API Gateway, .NET Messaging Service, data stores, durable broker, WebSocket updates, offline queue, push notifications, and read-receipt flow.

Useful Questions to Ask the Interviewer
  • Should both mobile and web clients use the same API?
  • How long should messages remain available for offline users?
  • Should delivery and read receipts appear in real time?
  • Should an offline user also receive a push notification?
Design a message-delivery API for a WhatsApp-like system. diagram
How to Explain It in an Interview
1. Define the client-facing API

I would start with the contract the client sees. The sender calls POST /v1/messages. The request carries Authorization: Bearer <JWT> and uses Content-Type: application/json. After the server accepts the message, the client receives 200 OK with messageId, serverTimestamp, and ack: SENT. SENT only means the server accepted the message. It does not mean the receiver has received or read it. The diagram also exposes GET /v1/messages/{id} for message and status, GET /v1/messages/conversations for listing messages, POST /v1/messages/{id}/read for read receipts, and WS /v1/stream for real-time events.

2. Pass the request through the API Gateway

The request first reaches the API Gateway. The gateway owns Authentication (JWT/OAuth2), Rate Limiting, Request Validation, and Routing / Load Balancing. It forwards the accepted request to the Messaging Service over HTTPS with mTLS. mTLS means the connection is encrypted and both sides can authenticate the transport connection. The diagram does not define exact failure status codes for these gateway checks, so I would not invent them.

3. Let the .NET Messaging Service own message processing

The Messaging Service contains the Message API, Connection Hub (WebSocket), Message Orchestrator, Fan-out & Routing, Offline Queue Manager, and Delivery & Read Processor. It reads and writes the Data Stores through ADO.NET / EF Core. Those stores contain Users & Contacts, Messages, Message Status, and Offline Queue data. After accepting a message, the service enqueues delivery tasks onto the Message Broker (Durable Queue). This keeps the client request separate from later delivery work.

4. Handle online and offline delivery

For an online user, the system uses the real-time delivery path and the user's WebSocket connection. The delivery acknowledgement represents DELIVERED, meaning the recipient device received the message. For an offline user, the message is stored in the offline path and receives the QUEUED state. The broker can also trigger the Push Notification Service for an offline user. That service uses FCM, APNs, or WNS. When the user comes online, the diagram shows a sync path for stored messages.

5. Surface acknowledgements through WebSocket events

The acknowledgement model has four meanings. SENT means the server accepted the message. QUEUED means the user is offline and the message is stored. DELIVERED means it reached the recipient device. READ means the recipient opened it. The real-time WebSocket area shows message.received, message.delivered, and message.read events. Keeping these states separate prevents the API from claiming that acceptance is the same as delivery or reading.

6. Process the read receipt separately

When the receiver reads a message, the client calls POST /v1/messages/{id}/read. The Delivery & Read Processor updates the status to READ. The sender is then notified through a WebSocket message.read event. The diagram shows the event carrying messageId, readBy, and timestamp. This keeps the original send request fast because reading happens later and follows its own flow.

7. Explain the main trade-off

The main decision is to separate synchronous acceptance from asynchronous delivery. The durable queue supports users who disconnect and later return. The downside is extra complexity. The system must keep message data, status data, queued work, push notifications, and WebSocket events consistent. The diagram does not claim exactly-once delivery or define retry rules, so I would not promise those guarantees.

Practical Complexity & Trade-offs

The benefit of this design is that sending a message does not depend on the receiver being online. The server can accept the message first and let the durable broker handle later work. This improves reliability for disconnected users. The downside is that more components must agree on message state. The API Gateway adds authentication, rate limiting, request validation, and routing before the request reaches the .NET service. HTTPS with mTLS protects the gateway-to-service connection. SQL stores keep messages, status, contacts, and offline data. WebSockets provide fast updates for connected users. The offline queue and push service handle disconnected users. The most important rule is to keep SENT, QUEUED, DELIVERED, and READ separate because each state proves something different.

Why Interviewers Ask This

Interviewers ask this question to test whether you can turn chat behavior into a clear API contract. They want to see correct request and response modeling, good acknowledgement semantics, and sensible handling of online and offline users. They also evaluate whether you place authentication, validation, storage, queuing, WebSocket delivery, and read-receipt responsibilities in the right components. Strong answers explain trade-offs without inventing delivery guarantees or failure behavior that the design does not support.

Interviewer may ask next
What happens if the recipient stays offline for a long time?

I would keep the same client-facing API and use the existing offline-delivery path. The sender still calls POST /v1/messages through the API Gateway. The .NET Messaging Service still accepts the message, stores its state, and puts delivery work on the durable Message Broker. Because the recipient is not connected by WebSocket, the Offline Queue Manager keeps the message available for later delivery and the acknowledgement becomes QUEUED. The broker can also trigger the Push Notification Service, which uses FCM, APNs, or WNS. When the user comes online, the diagram's sync path is used to deliver stored messages. After the recipient device receives a message, its state can move to DELIVERED. The API contract, gateway checks, message stores, and read-receipt flow remain unchanged. The benefit is that the sender does not wait for the receiver. The downside is extra stored state and queue work while the user remains offline. The diagram does not define an expiry period or retry schedule, so I would confirm those requirements with the interviewer instead of inventing them.

How are read receipts returned without slowing the original send request?

I would keep read receipts on the separate flow already shown in the design. The original POST /v1/messages request only needs to reach the server and return the SENT acknowledgement after acceptance. It does not wait for the recipient to open the message. Later, when the recipient reads it, that client calls POST /v1/messages/{id}/read. The Messaging Service's Delivery & Read Processor updates the Message Status data to READ. The system then surfaces the result to the sender through the WebSocket stream as a message.read event. The diagram shows that event carrying messageId, readBy, and timestamp. Authentication, rate limiting, validation, data storage, and the original delivery flow stay unchanged. This separation keeps sending responsive and gives the sender a real-time update when reading happens later. The downside is asynchronous state management: the stored status and emitted WebSocket event must represent the same read action. The design does not show an exactly-once guarantee, so I would not claim one.

20. Design an API surface for a customer-support ticket system.API DesignHardMicrosoft

Question Details

Define the operations a ticket API should expose for creation, assignment, state changes, and lookup by support agents or customers.

Short Interview Answer (30-60 seconds)

At a high level, I would use one ticket API for customers and support agents. Customers and agents send HTTPS requests with a JWT to an API Gateway. The gateway handles authentication, RBAC authorization, rate limiting, request validation, and routing. The ASP.NET Core Ticket API exposes ticket creation, assignment, state changes, comments, attachments, search, history, and supporting lookups. It reads and writes SQL Server and uses separate services for files, search, notifications, logging, and background events. The trade-off is more operational complexity for clearer responsibilities and safer side effects.

Detailed Explanation

This system helps customers ask for support and helps agents manage those requests. A customer needs a simple way to create a ticket, read updates, and continue the conversation. An agent needs a clear way to find work, assign it, change its state, and review what happened. The main challenge is keeping those actions easy to understand while protecting access and keeping slow side work away from the main request. I would follow the diagram from the two callers, through the gateway and Ticket API, then into storage and background services.

Useful Questions to Ask the Interviewer
  • Should customers be limited to their own tickets, while agents can see broader queues?
  • Which ticket state changes should each support role be allowed to make?
  • Is soft delete required for every ticket deletion, or only for normal user actions?
Design an API surface for a customer-support ticket system. diagram
How to Explain It in an Interview
1. Start with the callers and the gateway

I would begin with the customer web or mobile app and the support-agent web dashboard. Both send HTTPS requests with a JWT to the API Gateway. The gateway authenticates the JWT, applies RBAC authorization, rate limiting, request validation, and routing. RBAC means permissions depend on the caller's role. The gateway forwards the request over HTTPS to the Ticket API Service. The Ticket API returns a JSON response to the gateway, and the gateway returns that JSON to the caller.

2. Define the ticket and assignment operations

The main resource is the ticket. POST /api/tickets creates a new ticket. GET /api/tickets lists tickets with filtering, sorting, and pagination. GET /api/tickets/{id} gets one ticket. PATCH /api/tickets/{id} updates ticket details. DELETE /api/tickets/{id} performs the shown soft delete. Assignment uses explicit actions. POST /api/tickets/{id}/assign assigns a ticket to an agent or team. POST /api/tickets/{id}/unassign removes that assignment.

3. Keep state changes explicit

Important workflow changes have their own operations. POST /api/tickets/{id}/status changes the ticket state to open, pending, resolved, or closed. POST /api/tickets/{id}/reopen reopens a closed ticket. GET /api/ticket-statuses lists the allowed statuses. These explicit actions make the support workflow easier to understand and audit than hiding every transition inside a generic update.

4. Add comments, attachments, search, and supporting lookup

GET /api/tickets/{id}/comments lists comments, and POST /api/tickets/{id}/comments adds one. POST /api/tickets/{id}/attachments uploads an attachment. DELETE /api/attachments/{id} deletes an attachment. GET /api/tickets/search performs full-text search. GET /api/tickets/{id}/history returns status-change history, while GET /api/tickets/{id}/events returns ticket activity. Supporting lookups are GET /api/customers/me, GET /api/agents/me, and GET /api/teams.

5. Keep storage and integrations behind the Ticket API

The Ticket API reads and writes the Ticket Database in SQL Server through ADO.NET or EF Core. Query results return to the API as JSON. File upload and download use Blob Storage over HTTPS, and file metadata returns to the API. The API sends notifications over HTTPS to the Notification Service and receives delivery status. It indexes and queries the full-text Search Index and receives search results. It also writes logs and events to Audit & Logging and receives an acknowledgement. These are supporting flows, not the client response path.

6. Use domain events for slower side effects

The Ticket API publishes domain events such as NewTicket, StatusChanged, and CommentAdded to RabbitMQ or Azure Service Bus. A .NET hosted Background Worker Service consumes those events asynchronously and sends an acknowledgement to the broker. The worker handles email templates, integrations, SLA timers, archival, and similar side work. This keeps the main ticket request focused on the user action. I would also keep the API stateless with JWT authentication, use consistent JSON responses, preserve an audit trail for changes, and make operations idempotent where the operation allows it. The downside is more components to operate and monitor.

Practical Complexity & Trade-offs

The benefit is clear responsibility. The gateway handles JWT authentication, RBAC authorization, rate limiting, validation, and routing. The Ticket API owns ticket behavior and calls the database, file storage, search, notifications, and logging. Resource-based paths and normal HTTP verbs make the API easier to learn. Pagination, filtering, and sorting keep large ticket lists manageable. Soft delete helps preserve history, but deleted tickets must be handled carefully. Full-text search improves lookup, but the search index must stay aligned with ticket data. Idempotent operations, where appropriate, reduce accidental duplicate effects. Domain events move slower side work to the broker and worker. The downside is operational complexity because SQL Server, Blob Storage, search, notifications, logging, the broker, and workers all need monitoring.

Why Interviewers Ask This

Interviewers use this question to test API judgment rather than endpoint memorization. They want to see clear resource boundaries, sensible HTTP methods, and explicit operations for assignment and state changes. They also check whether you model the request and response path correctly, separate authentication from authorization, and place storage and side effects behind the API. Strong answers also explain pagination, search, audit logging, asynchronous work, and the trade-off between a simple client-facing API and more supporting infrastructure.

Interviewer may ask next
How would you handle a large increase in ticket volume without changing the API surface?

I would keep the same routes and scale the supporting paths independently. Customers and support agents would still send HTTPS requests with JWTs through the API Gateway, so authentication, RBAC authorization, rate limiting, validation, and routing stay unchanged. The Ticket API would continue to own ticket creation, assignment, status changes, comments, and lookup. GET /api/tickets would still use filtering, sorting, and pagination so large result sets stay controlled. Full-text lookup would continue through the Search Index instead of turning every search into a relational database scan. Slower side effects would remain asynchronous. The Ticket API would publish NewTicket, StatusChanged, and CommentAdded events to RabbitMQ or Azure Service Bus, and the .NET hosted worker would consume them separately. Correctness still depends on the Ticket API and database for ticket state, while the gateway keeps the same security checks. The downside is that higher volume increases operational work across SQL Server, search, the broker, workers, storage, notifications, and logging.

How would you keep customer and support-agent access safe when both use the same API?

I would keep the same API surface and use the gateway controls already shown. Both callers send HTTPS requests with a JWT. The API Gateway first authenticates the JWT, then applies RBAC authorization, which means the caller's role controls which operations are allowed. It also applies rate limiting and request validation before routing the request to the Ticket API. The exact customer-versus-agent permissions should be defined as policy, rather than guessed from the endpoint names. For example, the design can restrict assignment or state-change operations to approved support roles while keeping customer access limited according to the agreed rules. The Ticket API still owns the ticket operation and returns JSON through the gateway. Audit & Logging receives logs and events as a separate side flow, so security decisions and changes can be traced. The downside is policy complexity. As roles grow, RBAC rules must be kept simple, tested, and reviewed so users receive only the access they need.

More questions load as you scroll

Disclaimer: This interview guide is for educational and informational purposes only. It is designed to help readers prepare, but it does not guarantee any interview result, hiring decision, offer, or outcome. Interview questions, hiring criteria, and preferred answers can vary by employer, interviewer, industry, location, and time. The examples and explanations reflect the authors' research and judgment, are provided without warranties of any kind, and should not be treated as the only correct approach. Diagrams are simplified illustrations intended to highlight the main components and their interactions; actual systems and implementations may be more complex. Alternative approaches may be equally valid or better suited to a particular question, context, or interviewer. To the fullest extent permitted by applicable law, the author, contributors, and publisher are not liable for decisions made, actions taken, or losses incurred based on this guide.

Company Notice: This guide is an independent educational resource and is not affiliated with, endorsed by, sponsored by, or approved by the company named in this guide. Company names are used only to identify interview experiences commonly reported by candidates. Interview practices can change without notice, and inclusion of company-specific content does not mean these questions are official, complete, or guaranteed to be asked. To the fullest extent permitted by law, the author, contributors, and publisher are not responsible for outcomes related to use of this material.