Type-Safe API Client in TypeScript
Building robust and maintainable applications often involves interacting with external APIs. This challenge asks you to create a type-safe API client in TypeScript, ensuring that your code is protected from common errors related to API responses and data structures. A type-safe client will significantly improve developer experience and reduce runtime errors.
Problem Description
You are tasked with creating a TypeScript API client that interacts with a simplified weather API. The API provides weather data for a given city. The client should be type-safe, meaning it uses TypeScript's type system to ensure that the data received from the API matches the expected structure.
What needs to be achieved:
- Create a TypeScript class named
WeatherApiClient. - The class should have a method
getWeather(city: string)that fetches weather data for the specified city. - The
getWeathermethod should return a Promise that resolves to aWeatherDatainterface. - The
WeatherDatainterface should define the structure of the expected weather data (see below). - Implement a mock API endpoint to simulate the API response. This mock endpoint should return JSON data that conforms to the
WeatherDatainterface. - Handle potential errors during the API call (e.g., network errors, invalid city).
Key Requirements:
- Type Safety: The client must be type-safe, using TypeScript interfaces to define the expected data structure.
- Promise-based: The
getWeathermethod must return a Promise. - Error Handling: The client should handle potential errors gracefully and reject the Promise with an appropriate error message.
- Mock API: A mock API endpoint should be used for testing purposes. Do not use a real external API.
Expected Behavior:
- When
getWeather(city)is called with a valid city name, the Promise should resolve with aWeatherDataobject. - When
getWeather(city)is called with an invalid city name (e.g., an empty string or a city that doesn't exist in the mock API), the Promise should reject with an error message indicating that the city is invalid. - If a network error occurs during the API call, the Promise should reject with an error message indicating a network issue.
WeatherData Interface:
interface WeatherData {
city: string;
temperature: number;
condition: string;
windSpeed: number;
}
Examples
Example 1:
Input: WeatherApiClient.getWeather("London")
Output: { city: "London", temperature: 15, condition: "Cloudy", windSpeed: 10 }
Explanation: The API returns weather data for London, which is then returned by the Promise.
Example 2:
Input: WeatherApiClient.getWeather("")
Output: Promise rejected with error: "Invalid city name."
Explanation: An empty city name is considered invalid, so the Promise is rejected.
Example 3:
Input: WeatherApiClient.getWeather("Atlantis")
Output: Promise rejected with error: "City not found."
Explanation: Atlantis is not a valid city in the mock API, so the Promise is rejected.
Constraints
- The mock API endpoint should return data in JSON format.
- The
getWeathermethod should not take more than 500ms to execute (even with the mock API). - The
WeatherDatainterface must be defined as specified above. - Error messages should be clear and informative.
Notes
- You can use
fetchor any other HTTP client library to make the API request. For simplicity,fetchis recommended. - Consider using
async/awaitto simplify the asynchronous code. - The mock API endpoint can be implemented using a simple
setTimeoutto simulate network latency. - Focus on creating a clean, well-structured, and type-safe API client. Code readability and maintainability are important.
- Think about how you would handle different HTTP status codes (e.g., 404 Not Found) in a real-world scenario. For this exercise, focus on the core type-safety and error handling aspects.