Most Frequently asked Interview Questions of rest

author image Hirely
at 03 Jan, 2025

Question: What are idempotent and safe methods in REST?

Answer:

In RESTful API design, idempotent and safe methods refer to how HTTP methods behave with respect to repeated requests and the safety of side effects they may cause. Understanding these concepts is important for designing APIs that are reliable, predictable, and user-friendly.


Safe Methods:

A safe method is an HTTP method that does not modify the state of the server. It is used to retrieve information without causing any side effects on the data.

  • GET and HEAD are considered safe methods.
    • GET: Used to retrieve data from the server. Repeating a GET request will not change any data on the server.
    • HEAD: Similar to GET, but it retrieves only the headers, not the body of the response. It is also safe and doesn’t affect the server state.

Characteristics of Safe Methods:

  • Safe methods are only for retrieving data (reading).
  • Repeated execution of the request has no effect on the server or resource.
  • These methods should not change the state of the resource.

Example:

  • GET /users — Retrieves a list of users without modifying the data.

Idempotent Methods:

An idempotent method is an HTTP method that, when called multiple times with the same parameters, will produce the same result each time and does not have additional side effects. In other words, repeating an idempotent request should not change the outcome beyond the initial request.

  • GET, PUT, and DELETE are considered idempotent methods.
    • GET: As previously mentioned, it retrieves data without changing the server’s state. Repeated GET requests return the same data.
    • PUT: Used to update or create a resource. If the resource already exists, it will be updated with the same data, so multiple PUT requests with the same data will have the same result.
    • DELETE: Used to delete a resource. If the resource is already deleted, subsequent DELETE requests will result in the same outcome (i.e., resource is not found).

Characteristics of Idempotent Methods:

  • Idempotent methods can be safely repeated without unintended side effects.
  • Multiple calls with the same input will yield the same result as a single call.
  • These methods do not cause unintended modifications when repeated.

Example:

  • PUT /users/{id} — Updating a user’s information multiple times with the same data will always result in the same resource state.
  • DELETE /users/{id} — Deleting a user, whether it is done once or multiple times, will result in the user no longer existing in the system (after the first successful deletion).

Key Differences between Safe and Idempotent Methods:

CharacteristicSafe MethodsIdempotent Methods
DefinitionMethods that do not modify the state of the serverMethods that can be repeated without changing the result
Impact of Repeated CallsNo side effects, the state of the server does not changeRepeated calls with the same data result in the same outcome
ExamplesGET, HEADGET, PUT, DELETE
PurposeTo retrieve data without altering server stateTo modify or delete data, but without causing unintended effects on subsequent calls

Safe and Idempotent Methods in Practice:

  • GET: A safe and idempotent method. Calling GET /users multiple times will always return the same set of users (if the data does not change), without affecting the server state.

  • PUT: An idempotent method. Calling PUT /users/1 with the same data multiple times (e.g., { "name": "John Doe" }) will not cause any change after the first request, as the resource will always be updated with the same data.

  • DELETE: An idempotent method. Calling DELETE /users/1 once will delete the user. Calling it again will have no effect, as the user has already been deleted. It doesn’t cause further changes.


Non-Idempotent and Unsafe Methods:

  • POST: A method used to create new resources or perform actions that cause a change in state on the server. Unlike PUT, repeating a POST request can result in different outcomes, such as creating multiple resources.

    • Example: POST /users creates a new user. If called multiple times, new users will be created each time.
  • PATCH: A method used to apply partial updates to a resource. It is not necessarily idempotent because applying the same partial update multiple times can result in different states, depending on the current resource state.


Summary:

  • Safe methods (like GET and HEAD) are used to retrieve data without causing side effects.
  • Idempotent methods (like GET, PUT, and DELETE) can be safely repeated with the same parameters and will produce the same result each time.
  • Non-idempotent methods (like POST and PATCH) can cause different results when called multiple times with the same parameters, as they may create or modify resources.

By adhering to these principles, REST APIs can be more predictable, maintainable, and robust.

Question: How can you handle errors in RESTful services?

Answer:

Error handling is a crucial part of designing RESTful APIs. Proper error handling ensures that clients can understand what went wrong and how to fix it, providing a better user experience and making your API more predictable and easier to debug.

There are several ways to handle errors in RESTful services, including using HTTP status codes, providing meaningful error messages, and designing a structured error response format. Below are key strategies for handling errors effectively in RESTful APIs:


1. Use Appropriate HTTP Status Codes:

HTTP status codes should be used to communicate the result of the API request, including errors. Here’s a breakdown of common status codes for error handling:

  • 4xx - Client Errors: These status codes indicate that the request was invalid or there was an issue with the client’s input.

    • 400 Bad Request: The server cannot process the request due to invalid syntax. Example: Missing required parameters or invalid data format.
    • 401 Unauthorized: The client is not authenticated, or authentication failed.
    • 403 Forbidden: The client is authenticated but does not have permission to access the resource.
    • 404 Not Found: The requested resource could not be found on the server.
    • 405 Method Not Allowed: The HTTP method used is not supported for the requested resource.
    • 422 Unprocessable Entity: The request is well-formed, but the server cannot process it due to semantic errors (e.g., validation failures).
  • 5xx - Server Errors: These status codes indicate that the server failed to process the request, usually due to a problem on the server side.

    • 500 Internal Server Error: A generic error message indicating that the server encountered an unexpected condition.
    • 502 Bad Gateway: The server, while acting as a gateway or proxy, received an invalid response from the upstream server.
    • 503 Service Unavailable: The server is temporarily unable to handle the request, usually due to overloading or maintenance.
    • 504 Gateway Timeout: The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server.

2. Provide Detailed Error Responses:

In addition to using the appropriate HTTP status codes, you should provide meaningful error responses that help the client understand the cause of the error. This often includes an error code, a human-readable error message, and potentially additional details for troubleshooting.

Example of a well-structured error response:

{
  "error": {
    "code": "INVALID_PARAMETER",
    "message": "The 'email' field is required.",
    "details": [
      {
        "field": "email",
        "error": "Missing"
      }
    ]
  }
}
  • Error code: A machine-readable identifier for the error type (e.g., INVALID_PARAMETER).
  • Error message: A brief and human-readable explanation of the error (e.g., "The 'email' field is required.").
  • Details: Additional information to help the client understand the error context (e.g., specific fields with issues, or validation failures).

3. Return Consistent Error Structure:

Ensure that all error responses follow a consistent structure across your API. This consistency helps clients handle errors more easily and predictably.

A common structure might look like this:

{
  "status": "error",
  "message": "Invalid email address format.",
  "code": 400,
  "error_type": "validation_error"
}

Where:

  • status: Indicates whether the response was a success or failure (commonly "error" or "success").
  • message: A human-readable error message that provides context.
  • code: The HTTP status code associated with the error.
  • error_type: A specific type/category for the error (e.g., "validation_error").

4. Avoid Exposing Internal Details:

While it’s important to provide detailed error messages, avoid exposing sensitive internal details, like stack traces, database queries, or server-specific information, in error responses, especially in production environments.

For example, instead of returning an internal stack trace in the response body:

{
  "error": {
    "message": "Internal server error",
    "details": "java.lang.NullPointerException at ... "
  }
}

Return a generic error message that doesn’t reveal internal server details:

{
  "error": {
    "message": "An unexpected error occurred. Please try again later."
  }
}

This prevents potential security vulnerabilities and keeps your API user-friendly.


5. Use Exception Handling Mechanisms:

In your API backend, use exception handling mechanisms to catch errors before they reach the client. In case of an unexpected error (e.g., database failure, internal server error), the exception handler should log the error and return a standard error response to the client.

For example, in Java (using Spring Boot):

@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {
    ErrorResponse error = new ErrorResponse("RESOURCE_NOT_FOUND", ex.getMessage());
    return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}

This ensures that your API responds with structured, consistent error messages, regardless of the internal error that occurred.


6. Provide Useful Documentation:

Document the error responses and their meanings in your API documentation. Developers using your API will benefit from understanding what kind of errors can occur and how to handle them appropriately. For example, list the possible error codes, their meanings, and how clients should respond to them.


7. Handle Validation Errors Gracefully:

For errors due to invalid data (e.g., invalid JSON format, missing fields), return detailed validation error responses that tell the client exactly what is wrong.

For example:

{
  "status": "error",
  "message": "Validation failed.",
  "errors": [
    {
      "field": "email",
      "error": "Invalid email format"
    },
    {
      "field": "age",
      "error": "Must be 18 or older"
    }
  ]
}

This helps clients easily fix the request and ensures they know which fields need to be corrected.


8. Consider Using a Global Error Handler:

In larger applications, it’s a good idea to implement a global error handler to catch all unexpected exceptions and return a consistent error response.

For example, in Express.js, you can define a centralized error handler:

app.use((err, req, res, next) => {
  res.status(err.status || 500).json({
    status: 'error',
    message: err.message || 'Internal server error',
  });
});

This prevents repetitive error-handling code across various parts of your application and ensures uniformity.


9. Rate Limiting Errors:

If you’re implementing rate limiting, return a 429 status code (Too Many Requests) when the client exceeds the allowed number of requests in a given period.

Example:

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "You have exceeded the maximum number of requests. Please try again later."
  }
}

Optionally, include information about when the client can retry the request.


10. Use Logs and Monitoring:

While error messages help users understand what went wrong, you should also log errors for internal diagnostics and monitoring. Use a logging framework (like Log4j or Winston) and monitoring tools (like Sentry or New Relic) to capture and alert your team about critical errors or performance bottlenecks.


Summary:

Effective error handling in RESTful services is critical for providing a good developer experience and ensuring that clients can recover from and understand errors. Use:

  • Appropriate HTTP status codes to indicate the type of error.
  • Structured error responses with useful information.
  • Meaningful error messages that help users understand what went wrong.
  • Global error handlers to catch and handle unexpected errors consistently.

By following these best practices, you can ensure your API is robust, easy to use, and easier to debug for consumers.

Question: What is the difference between REST and GraphQL?

Answer:

REST and GraphQL are both approaches for building APIs, but they differ in how they handle data fetching, the structure of requests and responses, and flexibility. Here’s a detailed comparison of the two:


1. Data Fetching:

  • REST:

    • In REST, data is fetched through different endpoints for each resource. Each endpoint typically corresponds to a specific action or data entity (e.g., /users, /posts, /comments).
    • Each request typically retrieves all the data associated with that endpoint, which may include unwanted data.
    • For example, to retrieve a list of users and their posts, you might have to make two separate requests: one for /users and another for /posts.
  • GraphQL:

    • In GraphQL, data is fetched via a single endpoint (usually /graphql). Instead of having multiple endpoints for different resources, you send a query to the server that specifies exactly what data you need.
    • You can request multiple resources in a single query and only retrieve the data you need. This eliminates over-fetching or under-fetching of data.
    • For example, you can request a user and their posts in a single query:
      {
        user(id: 1) {
          name
          posts {
            title
            content
          }
        }
      }

2. Structure of Data:

  • REST:

    • REST APIs return predefined structures of data, typically in JSON format. The response structure depends on the endpoint and the HTTP method used.
    • If you need to adjust the data returned from an endpoint (e.g., only get a subset of fields), the server may need to implement custom query parameters or options.
  • GraphQL:

    • With GraphQL, the client specifies the structure of the response through the query. The server returns exactly what is requested, and nothing more.
    • This means clients have full control over the data they receive, which can help avoid over-fetching or under-fetching problems.

3. Flexibility:

  • REST:

    • REST APIs are generally more rigid in terms of what data is available. If you need additional data from a resource, you may need to either modify the API or make an additional request to another endpoint.
    • To retrieve related data (e.g., user and their posts), you often need to either:
      • Make multiple requests (e.g., /users then /posts).
      • Include embedded data within responses (e.g., users with embedded posts).
  • GraphQL:

    • GraphQL APIs offer much greater flexibility. Clients can request exactly the data they need from multiple resources in a single query, and they can specify the shape of the response.
    • This allows clients to avoid unnecessary data transfers and tailor the response to their needs, which is particularly useful for mobile or slow network environments.

4. Versioning:

  • REST:

    • REST APIs often require versioning to handle breaking changes. This is typically done using versioned endpoints (e.g., /v1/users, /v2/users).
    • Versioning can become cumbersome as the API evolves, especially when clients need to support multiple versions.
  • GraphQL:

    • GraphQL generally does not require versioning because it allows clients to specify exactly what data they need. As long as the schema evolves in a backward-compatible way (e.g., by adding new fields or types), older clients can continue working with the data they expect.
    • If new fields or types are added to the schema, clients simply don’t request those fields if they don’t need them.

5. Performance:

  • REST:
    • REST can suffer from over-fetching or under-fetching problems:
      • Over-fetching: You may retrieve more data than needed (e.g., fetching a large object when only a small subset of data is needed).
      • Under-fetching: If the data you need is scattered across multiple endpoints, you might need to make multiple requests.
  • GraphQL:
    • GraphQL minimizes over-fetching and under-fetching by allowing clients to specify exactly what data they need in a single query. This can lead to more efficient data fetching, especially when working with complex data structures.

6. Error Handling:

  • REST:

    • REST uses standard HTTP status codes (e.g., 200 OK, 404 Not Found, 500 Internal Server Error) to indicate the result of the request.
    • Errors are typically returned as part of the HTTP response body with a message and possibly an error code.
  • GraphQL:

    • GraphQL does not use standard HTTP status codes. Instead, it always returns a 200 OK status code, even if the query has errors, as long as the request itself is valid.
    • Errors are returned in a structured errors field within the response, separate from the data:
      {
        "data": { "user": null },
        "errors": [
          {
            "message": "User not found",
            "locations": [{ "line": 1, "column": 3 }],
            "path": ["user"],
            "extensions": { "code": "USER_NOT_FOUND" }
          }
        ]
      }

7. Use Cases:

  • REST:
    • REST is often better suited for simpler APIs where you have a clear resource model (e.g., CRUD operations on users, products, orders).
    • REST works well when the client needs to interact with resources in a relatively straightforward manner (e.g., reading, updating, or deleting specific resources).
  • GraphQL:
    • GraphQL is more suited for complex applications where clients need to interact with multiple resources or where the structure of the data may evolve over time.
    • It’s especially useful for mobile applications or environments with slow networks, as it allows clients to request exactly the data they need, avoiding over-fetching and reducing bandwidth usage.

8. Caching:

  • REST:
    • REST APIs can leverage traditional HTTP caching mechanisms, like ETags, Cache-Control, and Last-Modified headers, to cache responses at the HTTP level.
  • GraphQL:
    • Caching in GraphQL is more complex, as the responses can vary depending on the query structure and parameters.
    • To implement caching, developers often use client-side libraries (e.g., Apollo Client) that can cache GraphQL responses on a per-query basis, rather than relying on traditional HTTP caching.

Summary of Key Differences:

FeatureRESTGraphQL
EndpointMultiple endpoints (e.g., /users, /posts)Single endpoint (/graphql)
Data FetchingFetches all data from an endpoint, potentially over-fetchingFetches exactly what is requested in a query
Response StructureFixed response structure per endpointFlexible, client-defined response structure
VersioningRequires versioning (e.g., /v1/)No versioning required, evolves over time
PerformanceCan lead to over-fetching or under-fetchingPrevents over-fetching and under-fetching
Error HandlingUses standard HTTP status codesUses structured error field in response
Use CaseSimpler, more straightforward APIsComplex, flexible APIs, especially with related resources
CachingLeverages traditional HTTP caching mechanismsRequires custom caching solutions or client libraries
FlexibilityLess flexible, fixed resources per endpointHighly flexible, client defines data shape

Conclusion:

  • REST is a simpler, more traditional approach, ideal for applications with clear, stable resources and relatively straightforward CRUD operations.
  • GraphQL offers more flexibility, allowing clients to fetch exactly the data they need and reducing the need for multiple requests. It is better suited for complex applications, especially with evolving data models and multiple related resources.

Question: How do you handle pagination in a REST API?

Answer:

Pagination is a technique used in APIs to divide large datasets into smaller, more manageable chunks (pages). This is especially important when the data set could potentially be very large, and returning all data in a single response would be inefficient or could overwhelm the client or server.

Here are the most common ways to handle pagination in a REST API:


1. Limit and Offset Pagination

This is one of the simplest and most widely used pagination methods. It involves using limit and offset (or page and size) query parameters to specify which page of results to retrieve and how many results to return.

  • limit: Specifies the maximum number of items to return per page.
  • offset: Specifies the starting point (index) for the current page.

Example:

GET /api/products?limit=10&offset=20

This request will retrieve 10 products starting from the 21st product (index 20).

Response:

{
  "data": [ /* 10 products */ ],
  "meta": {
    "total": 100,
    "limit": 10,
    "offset": 20
  }
}
  • Pros: Simple to implement and understand.
  • Cons: Can become inefficient for large datasets as the offset value grows larger (e.g., the database has to skip over more and more records).

2. Page-based Pagination

In this approach, pagination is handled using page numbers and page sizes.

  • page: The current page number (usually starts from 1).
  • size: The number of items to return per page.

Example:

GET /api/products?page=3&size=10

This request will retrieve the 3rd page of products, with 10 products per page.

Response:

{
  "data": [ /* 10 products */ ],
  "meta": {
    "total": 100,
    "page": 3,
    "size": 10
  }
}
  • Pros: Easier for clients to calculate, and often better for user-facing pagination (e.g., “Page 3 of 10”).
  • Cons: Still involves a linear scan of the data and can be inefficient with large datasets.

3. Cursor-based Pagination (Keyset Pagination)

Cursor-based pagination uses a cursor (a unique identifier or pointer) to paginate through data. This is more efficient than offset-based pagination because it avoids large skips in the database.

In cursor-based pagination:

  • after: The cursor that points to the last item of the previous page.
  • before: The cursor that points to the first item of the previous page.

The client requests the next set of results starting from a known position (cursor), rather than skipping over records by offset.

Example:

GET /api/products?limit=10&after=eyJpZCI6MTIzfQ==

Here, the after query parameter contains the cursor, which represents the last record of the previous page. The server returns the next 10 products starting after this cursor.

Response:

{
  "data": [ /* 10 products */ ],
  "meta": {
    "next": "eyJpZCI6NDU2fQ=="
  }
}
  • Pros: More efficient, particularly for large datasets, as it doesn’t require skipping over records.
  • Cons: More complex to implement. Clients need to manage and store cursors.

4. Timestamp-based Pagination

In this method, pagination is done based on a timestamp or other unique, sequential identifier (e.g., an auto-incrementing id). The client requests items that come after or before a certain timestamp or identifier.

Example:

GET /api/products?created_after=2023-01-01T00:00:00Z&limit=10

This would fetch products that were created after January 1st, 2023, and return the next 10 products.

Response:

{
  "data": [ /* 10 products */ ],
  "meta": {
    "next": "2023-01-02T00:00:00Z"
  }
}
  • Pros: Efficient, particularly when data is naturally ordered by time or sequential identifiers.
  • Cons: Not suitable for all types of data; requires a sortable field (e.g., timestamp or unique ID).

It is a good practice to provide hypermedia links (HATEOAS) to assist the client in navigating between pages. These links allow the client to retrieve the next, previous, first, and last pages of results.

{
  "data": [ /* 10 products */ ],
  "meta": {
    "total": 100,
    "limit": 10,
    "offset": 20
  },
  "links": {
    "self": "/api/products?limit=10&offset=20",
    "next": "/api/products?limit=10&offset=30",
    "prev": "/api/products?limit=10&offset=10"
  }
}
  • Pros: Simplifies navigation for the client, as they don’t need to manage the pagination logic manually.
  • Cons: Requires careful planning to manage the generation of links for each page.

Best Practices for Pagination in REST APIs:

  1. Limit the size of each page to avoid overwhelming the client or server. A typical page size might range from 10 to 100 items, but this can vary based on the use case.
  2. Include total count of items in the response when possible, so the client knows how many items exist in total (useful for UI pagination controls).
  3. Use consistent query parameters across your API to make pagination predictable (e.g., limit and offset or page and size).
  4. Handle edge cases like empty result sets or the last page of results.
  5. Consider cursor-based pagination if your dataset is large or continuously changing, as it avoids performance issues with offset-based pagination.
  6. Provide pagination links (HATEOAS) to help clients navigate through pages without needing to manually construct the next page URLs.

Summary of Pagination Methods:

MethodDescriptionBest ForProsCons
Limit and OffsetUses limit and offset parameters to paginate.Simple, small datasets or predictable data.Easy to implement.Inefficient for large datasets.
Page-basedUses page and size to paginate.User-facing applications with known data sizes.User-friendly.Can be inefficient for large datasets.
Cursor-basedUses a cursor to point to the last item of the previous page.Large or continuously changing datasets.Efficient, avoids over-fetching.Complex implementation.
Timestamp-basedUses timestamp or sequential ID to paginate.Time-ordered or sequential data.Efficient for time-based data.Requires an appropriate field (timestamp, ID).
Pagination Links (HATEOAS)Uses hypermedia links for navigation.Client-side navigation support.Simplifies client logic.Can be more complex to manage.

By choosing the right pagination strategy based on your use case and data size, you can ensure efficient API responses and a better experience for consumers of your API.

Read More

If you can’t get enough from this article, Aihirely has plenty more related information, such as rest interview questions, rest interview experiences, and details about various rest job positions. Click here to check it out.

Trace Job opportunities

Hirely, your exclusive interview companion, empowers your competence and facilitates your interviews.

Get Started Now