Skip to content
HackerRank AI Day will unveil new innovations in AI and feature industry thought leaders. Read agenda
The 2024 Developer Skills Report is here! Sneak peak
Career Growth

6 REST API Interview Questions Every Developer Should Know

Written By April Bohnert | September 7, 2023

Abstract, futuristic image generated by AI

APIs — or application programming interfaces — play a key role in the software ecosystem. In a tech world that hinges on its interconnectedness, APIs serve as the vital middlemen that enable different pieces of software to work together seamlessly. And in the realm of APIs, REST (Representational State Transfer) stands as one of the most popular architectures. Why? Because it’s simple, scalable, and can handle multiple types of calls, return different data formats, and even change structurally with the correct implementation of hypermedia.

Given the ubiquitous role of REST APIs in modern software development, it’s not an overstatement to say that strong REST API skills are a must-have for developers across various disciplines — from full-stack and back-end developers to data scientists. But let’s not forget the recruiters and hiring managers striving to find the best talent. Knowing what questions to ask and what tasks to set during a technical interview can make a world of difference in finding the right hire.

In this blog post, we’re going to delve into what a REST API is, look at what you can expect from a REST API interview, and provide some challenging coding questions aimed at testing a developer’s REST API expertise. Whether you’re a developer looking to prepare for your next interview or a recruiter aiming to assess candidates proficiently, this post aims to be your go-to guide.

What is a REST API?

REST, short for representational state transfer, is an architectural style that sets the standard for creating web services. A REST API, therefore, is a set of conventions and rules for building and interacting with those services. 

The key components that define this architectural style include:

  • Resources: In REST, you interact with resources, which are essentially objects like users, products, or orders, represented as URLs or endpoints.
  • HTTP Methods: These resources are manipulated using standard HTTP methods. You’ve got GET for reading, POST for creating, PUT for updating, and DELETE for, well, deleting.
  • Stateless Interactions: REST APIs operate on a stateless basis. Every API request from a client to a server must contain all the information needed to process the request. This is one of the reasons why REST APIs are so scalable.

Simplicity, scalability, and versatility are hallmarks of REST APIs — and are some of the key reasons why this API protocol is so popular. REST APIs employ straightforward HTTP methods, are built to scale, and can return data in various formats (most commonly JSON and XML). With such attributes, plus strong community and library support, REST APIs have become the crucial connective tissue linking different services, applications, and systems in an increasingly integrated tech world.

What a REST API Interview Looks Like

When you’re sitting down for a REST API interview — either as a candidate eager to showcase your skills or as a member of a hiring team aiming to discover top talent — know that the focus will go beyond basic programming. You’ll explore the depths of HTTP methods, status codes, API endpoints, and the intricacies of data manipulation and retrieval. Understanding REST isn’t just about knowing the syntax; it’s about grasping the architecture, the philosophy, and the best practices that guide efficient API design and usage.

In this context, you may be asked to handle a variety of challenges:

  • Conceptual discussions about REST principles to gauge your foundational knowledge.
  • Hands-on coding tasks that require you to implement specific API calls, perhaps even integrating third-party services.
  • Debugging exercises where you’re given pieces of a RESTful service and asked to identify issues or optimize performance.
  • Scenarios where you have to design RESTful routes and resources, showcasing your understanding of RESTful best practices.

So who needs to be proficient in REST APIs? Well, you’d be hard-pressed to find a technical role that doesn’t benefit from REST API skills. However, they’re particularly essential for:

  • Back-End Developers: The architects behind the server-side logic, often responsible for setting up the API endpoints.
  • Full-Stack Developers: The jacks-of-all-trades who need to know both client-side and server-side technologies, including APIs.
  • API Developers: Those specializing in API development, obviously.
  • Data Scientists and Engineers: Professionals who need to pull in data from various services for analytics and data processing.
  • Mobile App Developers: Many mobile apps pull from web services, often using REST APIs.
  • QA Engineers: Those responsible for testing the reliability and scalability of web services, including APIs.

1. Create a Simple RESTful Service to Manage a To-Do List

This question serves as a foundational task to assess your grasp of REST API basics, CRUD operations, and endpoint creation.

Task: Write a Python function using the Flask framework to manage a simple to-do list. Your API should support the following operations: adding a new task, getting a list of all tasks, updating a task description, and deleting a task.

Input Format: For adding a new task, the input should be a JSON object like `{“task”: “Buy groceries”}`.

Constraints:

  • The task description will be a non-empty string.
  • Each task will have a unique identifier.

Output Format: The output should also be in JSON format. For fetching all tasks, the output should look like `[{“id”: 1, “task”: “Buy groceries”}, {“id”: 2, “task”: “Read a book”}]`.

Sample Code:

from flask import Flask, jsonify, request

app = Flask(__name__)

tasks = []

task_id = 1

@app.route('/tasks', methods=['GET'])

def get_tasks():

    return jsonify(tasks)

@app.route('/tasks', methods=['POST'])

def add_task():

    global task_id

    new_task = {"id": task_id, "task": request.json['task']}

    tasks.append(new_task)

    task_id += 1

    return jsonify(new_task), 201

@app.route('/tasks/<int:id>', methods=['PUT'])

def update_task(id):

    task = next((item for item in tasks if item['id'] == id), None)

    if task is None:

        return jsonify({"error": "Task not found"}), 404

    task['task'] = request.json['task']

    return jsonify(task)

@app.route('/tasks/<int:id>', methods=['DELETE'])

def delete_task(id):

    global tasks

    tasks = [task for task in tasks if task['id'] != id]

    return jsonify({"result": "Task deleted"})

Explanation:  

The Python code uses Flask to set up a simple RESTful API. It has four endpoints corresponding to CRUD operations for managing tasks. `GET` fetches all tasks, `POST` adds a new task, `PUT` updates a task based on its ID, and `DELETE` removes a task by its ID.

2. Implement Pagination in a REST API

This question is designed to gauge your understanding of pagination, a technique often used in REST APIs to manage large sets of data.

Task: Modify the previous Python Flask API for managing tasks to include pagination. The API should return a subset of tasks based on `limit` and `offset` query parameters.

Input Format: For fetching tasks, the API URL could look like `/tasks?offset=2&limit=3`.

Constraints:

  • The `offset` will be a non-negative integer.
  • The `limit` will be a positive integer.

Output Format:  

The output should be in JSON format, returning tasks based on the given `offset` and `limit`.

Sample Code:

@app.route('/tasks', methods=['GET'])

def get_tasks():

    offset = int(request.args.get('offset', 0))

    limit = int(request.args.get('limit', len(tasks)))

    paginated_tasks = tasks[offset:offset+limit]

    return jsonify(paginated_tasks)

Explanation:  

In this modification, the `get_tasks` function now uses the `offset` and `limit` query parameters to slice the `tasks` list. This way, it only returns a subset of tasks based on those parameters. It’s a simple yet effective way to implement pagination in a REST API.

Explore verified tech roles & skills.

The definitive directory of tech roles, backed by machine learning and skills intelligence.

Explore all roles

3. Implement Basic Authentication

Authentication is crucial in APIs to ensure only authorized users can perform certain actions. This question tests your knowledge of implementing basic authentication in a REST API.

Task: Modify the previous Flask API for managing tasks to require basic authentication for all operations except retrieving the list of tasks (`GET` method).

Input Format: API requests should include basic authentication headers.

Constraints: For simplicity, assume a single user with a username of “admin” and a password of “password.”

Output Format: Unauthorized requests should return a 401 status code. Otherwise, the API behaves as in previous examples.

Sample Code:

from flask import Flask, jsonify, request, abort

from functools import wraps

app = Flask(__name__)

# ... (previous code for task management)

def check_auth(username, password):

    return username == 'admin' and password == 'password'

def requires_auth(f):

    @wraps(f)

    def decorated(*args, **kwargs):

        auth = request.authorization

        if not auth or not check_auth(auth.username, auth.password):

            abort(401)

        return f(*args, **kwargs)

    return decorated

@app.route('/tasks', methods=['POST', 'PUT', 'DELETE'])

@requires_auth

def manage_tasks():

    # ... (previous code for POST, PUT, DELETE methods)

Explanation:  

In this example, the `requires_auth` decorator function checks for basic authentication in incoming requests. The `check_auth` function simply validates the username and password. If the credentials are incorrect or missing, the server returns a 401 status code. This decorator is applied to routes requiring authentication (`POST`, `PUT`, `DELETE`).

4. Implement Rate Limiting

Rate limiting is used to control the amount of incoming requests to a server. This question evaluates your understanding of how to set up rate limiting in a RESTful service.

Task: Add rate limiting to your Flask API for managing tasks. Limit each client to 10 requests per minute for any type of operation.

Input Format: Standard API requests, same as previous examples.

Constraints: Rate limiting should apply per client IP address.

Output Format: Clients exceeding the rate limit should receive a 429 status code and the message “Too many requests.”

Sample Code:

from flask import Flask, jsonify, request, abort, make_response

from time import time

from functools import wraps

app = Flask(__name__)

client_times = {}

def rate_limit(f):

    @wraps(f)

    def decorated(*args, **kwargs):

        client_ip = request.remote_addr

        current_time = int(time())
    
        requests = client_times.get(client_ip, [])       

        # Filter requests in the last minute

        requests = [req_time for req_time in requests if current_time - req_time < 60]

        if len(requests) >= 10:

            return make_response(jsonify({"error": "Too many requests"}), 429)
       
        requests.append(current_time)

        client_times[client_ip] = requests
       
        return f(*args, **kwargs)
   
    return decorated

@app.route('/tasks', methods=['GET', 'POST', 'PUT', 'DELETE'])

@rate_limit

def manage_tasks():

    # ... (previous code for GET, POST, PUT, DELETE methods)

Explanation:  

The `rate_limit` decorator function checks how many times a client has made a request within the last minute. It uses a global `client_times` dictionary to keep track of these request times, keyed by client IP. If a client exceeds 10 requests, a 429 status code (“Too many requests”) is returned.

5. Implement API Versioning

When APIs evolve, maintaining different versions ensures older clients aren’t broken by new updates. This question tests your skills in implementing versioning in a RESTful service.

Task: Extend your Flask API for task management to support both a `v1` and a `v2` version. In `v2`, the task object should include an additional field called `status`.

Input Format: The version of the API should be specified in the URL, like `/v1/tasks` and `/v2/tasks`.

Constraints: The `status` field in `v2` is a string and can have values “pending,” “completed,” or “archived.”

Output Format: For `v1`, the task object remains the same as before. For `v2`, it should include the `status` field.

Sample Code:

from flask import Flask, jsonify, request

app = Flask(__name__)

tasks_v1 = []

tasks_v2 = []

task_id = 1

@app.route('/v1/tasks', methods=['GET', 'POST'])

def manage_tasks_v1():

    global task_id

    # ... (previous code for v1)

    return jsonify(tasks_v1)

@app.route('/v2/tasks', methods=['GET', 'POST'])

def manage_tasks_v2():

    global task_id

    if request.method == 'POST':

        new_task = {"id": task_id, "task": request.json['task'], "status": "pending"}

        tasks_v2.append(new_task)

        task_id += 1

        return jsonify(new_task)

    return jsonify(tasks_v2)

Explanation:  

The code includes two routes for task management, `/v1/tasks` and `/v2/tasks`. The `v1` route behaves as in previous examples. The `v2` route includes an additional `status` field in the task object, initialized to “pending” when a new task is added.

6. Custom HTTP Status Codes and Error Handling

Proper error handling and status codes make an API user-friendly and easier to debug. This question targets your knowledge of using appropriate HTTP status codes for various scenarios.

Task: Update your Flask API to return custom error messages along with appropriate HTTP status codes for different error scenarios.

Input Format: Standard API requests, same as previous examples.

Constraints:

  • Return a 404 status code with a custom message if a task is not found.
  • Return a 400 status code with a custom message if the input payload is missing necessary fields.

Output Format: The API should return JSON-formatted error messages along with appropriate HTTP status codes.

Sample Code:

from flask import Flask, jsonify, request, make_response

app = Flask(__name__)

tasks = []

@app.route('/tasks/<int:task_id>', methods=['GET', 'PUT', 'DELETE'])

def manage_single_task(task_id):

    task = next((item for item in tasks if item['id'] == task_id), None)

    if task is None:

        return make_response(jsonify({"error": "Task not found"}), 404)      

    if request.method == 'PUT':

        if 'task' not in request.json:

            return make_response(jsonify({"error": "Missing fields in request"}), 400)       

        task['task'] = request.json['task']

        return jsonify(task)

    # ... (previous code for GET and DELETE methods)

Explanation:  

In this example, the `manage_single_task` function first checks if the task exists. If not, it returns a 404 status code with a custom error message. If the task exists and it’s a `PUT` request but missing the ‘task’ field, it returns a 400 status code with another custom error message.

Resources to Improve REST API Knowledge

This article was written with the help of AI. Can you tell which parts?

Abstract, futuristic image generated by AI

What Is a REST API? Bridging the Gap Between Software