Back to: ASP.NET Core Web API Tutorials
How to Implement HTTP GET Method in ASP.NET Core Web API
In this article, I will discuss How to Implement the HTTP GET Method in ASP.NET Core Web API Application with Real-Time Examples. Please read our previous article discussing HTTP Methods in ASP.NET Core Web API with Examples.
HTTP GET Method
The HTTP GET method is one of the Hypertext Transfer Protocol (HTTP) methods used to request data from a specified resource. In the context of the World Wide Web, it is one of the most common methods for retrieving information. Here are key aspects of the HTTP GET method:
Definition and Usage
- Purpose: The GET method is designed to retrieve information from the server. GET requests should only retrieve data and should have no other effect on it.
- Idempotency: GET requests are considered idempotent, meaning that making multiple identical requests has the same effect as making a single request.
- Safe: GET requests are considered safe as they do not modify the server state.
Features
- URL Encoding: The Parameters of a GET request are appended to the request URL in the form of a query string. For example, http://example.com/api?param1=value1¶m2=value2. This can include search parameters or identifiers needed to retrieve the desired data.
- Length Limitation: Since GET Request parameters are passed in the URL, they are subject to URL length limitations, which can vary by browser and server. This can limit the amount of data that can be sent in a GET request.
- Caching: Responses to GET requests are often cacheable, either by the browser or by intermediary proxies, which can improve performance for repeat requests to the same resource.
HTTP Response
- Status Codes: The server’s response to a GET request includes a status code indicating the request’s result, such as 200 OK for success, 404 Not Found for a resource that cannot be found, or 403 Forbidden for restricted resources.
How to Implement HTTP GET Method in ASP.NET Core Web API
The HTTP GET method is used in the ASP.NET Core Web API to retrieve data from a server at the specified resource. Implementing the HTTP GET method in the ASP.NET Core Web API Application involves creating a controller action that handles GET requests to retrieve data from the server. Let us understand this with an example:
Define Models
Create the following C# classes in the Models folder representing the data we will work with. You can create a Models folder if your project doesn’t have a Models folder. So, create a class file named Order.cs and then copy and paste the following code:
namespace HTTPMethodDemo.Models { public class Order { public int Id { get; set; } public int UserId { get; set; } public decimal TotalAmount { get; set; } } }
Next, create another class file named User.cs and then copy and paste the following code:
namespace HTTPMethodDemo.Models { public class User { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public ICollection<Order> Orders { get; set; } = new List<Order>(); } }
Create a Service
For real-world applications, we typically interact with a database or another data source, such as restful services. So, create a class file named UserRepository.cs and copy and paste the following code. Here, we are not interacting with the database, but for simplicity, we are working with in-memory data.
namespace HTTPMethodDemo.Models { public class UserRepository { public List<User> Users = new List<User>() { new User() { Id = 1, Name= "Pranaya", Email = "Pranaya@Example.com" }, new User() { Id = 2, Name= "Anurag", Email = "Anurag@Example.com" }, new User() { Id = 3, Name= "Priyanka", Email = " Priyanka@Example.com" } }; public List<Order> Orders = new List<Order>() { new Order() { Id = 1001, UserId = 1, TotalAmount = 100}, new Order() { Id = 1002, UserId = 2, TotalAmount = 200}, new Order() { Id = 1003, UserId = 1, TotalAmount = 300}, new Order() { Id = 1004, UserId = 2, TotalAmount = 400}, new Order() { Id = 1005, UserId = 3, TotalAmount = 500} }; // Get All Users public IEnumerable<User> GetAll() { var users = Users.ToList(); foreach (var user in users) { user.Orders = Orders.Where(ord => ord.UserId == user.Id).ToList(); } return users; } // Get a user by ID public User GetById(int Id) { var user = Users.FirstOrDefault(u => u.Id == Id); if (user != null) { user.Orders = Orders.Where(ord => ord.UserId == user.Id).ToList(); } return user; } // Search users by name public IEnumerable<User> SearchByName(string name) { var users = Users.Where(u => u.Name.Contains(name)).ToList(); foreach (var user in users) { user.Orders = Orders.Where(ord => ord.UserId == user.Id).ToList(); } return users; } // Get orders by user ID public IEnumerable<Order> GetOrderByUserId(int UserId) { var userWithOrders = Orders.Where(ord => ord.UserId == UserId); return userWithOrders ?? new List<Order>(); } } }
Here,
- GetAll Method: This method retrieves all users from the database, including their related orders.
- GetById Method: This method finds a single user by their ID, including their orders. It uses FirstOrDefault to return either the matching user or null if no user is found.
- SearchByName Method: This method allows users to be searched by their name. It uses the Contains method to perform a case-sensitive search within each user’s Name property.
- GetOrderByUserId Method: This method retrieves all orders for a specific user using the user’s ID.
Registering the Service:
Please add the following statement to the Program.cs class file. This will add the service to the dependency injection container.
builder.Services.AddScoped<UserRepository>();
Implement the Controller
Create a new Empty API Controller named UsersController in the Controllers directory. This involves inheriting from the ControllerBase class and annotating the class with [ApiController] and [Route(“api/[controller]”)] attributes. Once you create the UsersController, copy and paste the following code.
using HTTPMethodDemo.Models; using Microsoft.AspNetCore.Mvc; namespace HTTPMethodDemo.Controllers { [Route("api/[controller]")] [ApiController] public class UsersController : ControllerBase { private readonly UserRepository _userRepository; public UsersController(UserRepository userRepository) { _userRepository = userRepository; } //Endpoint to retrieve all users //GET api/users [HttpGet] public ActionResult<List<User>> GetAllUsers() { var users = _userRepository.GetAll(); return Ok(users); } //Endpoint to fetch details of a specific user by Id //GET api/users/1 [HttpGet] [Route("api/users/{Id}")] public ActionResult<User> GetUser(int Id) { var user = _userRepository.GetById(Id); if (user == null) { return NotFound(); } return Ok(user); } //Endpoint for searching users by name (query parameter) //GET api/users/search?name=pranaya [HttpGet] [Route("search")] public ActionResult<List<User>> SearchUsers(string name) { var users = _userRepository.SearchByName(name); if(users == null || !users.Any()) { return NotFound(); } return Ok(users); } //Endpoint to get all orders for a specific user //GET api/users/1/orders [HttpGet] [Route("api/users/{userId}/orders")] public ActionResult<List<Order>> GetUserOrders(int userId) { var orders = _userRepository.GetOrderByUserId(userId); if (orders == null || !orders.Any()) { return NotFound(); } return Ok(orders); } } }
Now, run the application and test the API endpoints, and it should work as expected:
API: Get All Users along with Orders
URL: https://localhost:7047/api/Users
Method: GET
Using Postman:
API: Fetch User by User ID
URL: https://localhost:7047/api/Users
Method: GET
Using Postman:
API: Search User by Name
URL: https://localhost:7047/api/Users/search?name=Priyanka
Method: GET
Using Postman:
API: Get Order by User ID
URL: https://localhost:7047/api/Users/1?orders
Method: GET
Using Postman:
Implementing Asynchronous HTTP GET Method in ASP.NET Core Web API:
In most of the real-time applications, we need to make the action methods or services async if it is performing some I/O operations. That means if it is doing some database operations or invoking other services, we should do it asynchronously to improve the application performance. Let us see how we can implement this.
Modifying the UserRepository:
First, modify the UserRepository.cs class file as follows. Here, we are making the methods async. Here, you will get some warning because we are not using the await keyword. To ignore the warning, we are delaying the execution of the action method by 1 second, and let’s assume this is the time period that the server will take to communicate with the database and perform the operation. Also, we changed the method name by appending the word Async.
namespace HTTPMethodDemo.Models { public class UserRepository { public List<User> Users = new List<User>() { new User() { Id = 1, Name= "Pranaya", Email = "Pranaya@Example.com" }, new User() { Id = 2, Name= "Anurag", Email = "Anurag@Example.com" }, new User() { Id = 3, Name= "Priyanka", Email = "Priyanka@Example.com" } }; public List<Order> Orders = new List<Order>() { new Order() { Id = 1001, UserId = 1, TotalAmount = 100}, new Order() { Id = 1002, UserId = 2, TotalAmount = 200}, new Order() { Id = 1003, UserId = 1, TotalAmount = 300}, new Order() { Id = 1004, UserId = 2, TotalAmount = 400}, new Order() { Id = 1005, UserId = 3, TotalAmount = 500} }; // Get All Users public async Task<IEnumerable<User>> GetAll() { var users = Users.ToList(); foreach (var user in users) { user.Orders = Orders.Where(ord => ord.UserId == user.Id).ToList(); } await Task.Delay(TimeSpan.FromSeconds(1)); return users; } // Get a user by ID public async Task<User> GetById(int Id) { var user = Users.FirstOrDefault(u => u.Id == Id); if (user != null) { user.Orders = Orders.Where(ord => ord.UserId == user.Id).ToList(); } await Task.Delay(TimeSpan.FromSeconds(1)); return user; } // Search users by name public async Task<IEnumerable<User>> SearchByName(string name) { var users = Users.Where(u => u.Name.Contains(name)).ToList(); foreach (var user in users) { user.Orders = Orders.Where(ord => ord.UserId == user.Id).ToList(); } await Task.Delay(TimeSpan.FromSeconds(1)); return users; } // Get orders by user ID public async Task<IEnumerable<Order>> GetOrderByUserId(int UserId) { var userWithOrders = Orders.Where(ord => ord.UserId == UserId); await Task.Delay(TimeSpan.FromSeconds(1)); return userWithOrders ?? new List<Order>(); } } }
Modifying the UsersController:
Next, modify the UsersController as follows to make the action method Asynchronous. Also, we use the await keyword while calling the UserRepository services.
using HTTPMethodDemo.Models; using Microsoft.AspNetCore.Mvc; namespace HTTPMethodDemo.Controllers { [Route("api/[controller]")] [ApiController] public class UsersController : ControllerBase { private readonly UserRepository _userRepository; public UsersController(UserRepository userRepository) { _userRepository = userRepository; } //Endpoint to retrieve all users //GET api/users [HttpGet] public async Task<ActionResult<List<User>>> GetAllUsers() { var users = await _userRepository.GetAllAsync(); return Ok(users); } //Endpoint to fetch details of a specific user by Id //GET api/users/1 [HttpGet] [Route("api/users/{Id}")] public async Task<ActionResult<User>> GetUser(int Id) { var user = await _userRepository.GetByIdAsync(Id); if (user == null) { return NotFound(); } return Ok(user); } //Endpoint for searching users by name (query parameter) //GET api/users/search?name=pranaya [HttpGet] [Route("search")] public async Task<ActionResult<List<User>>> SearchUsers(string name) { var users = await _userRepository.SearchByNameAsync(name); if(users == null || !users.Any()) { return NotFound(); } return Ok(users); } //Endpoint to get all orders for a specific user //GET api/users/1/orders [HttpGet] [Route("api/users/{userId}/orders")] public async Task<ActionResult<List<Order>>> GetUserOrders(int userId) { var orders = await _userRepository.GetOrderByUserIdAsync(userId); if (orders == null || !orders.Any()) { return NotFound(); } return Ok(orders); } } }
With the above changes in place, run the application and test all the endpoints, and it should work as expected.
GET Request URL Length Limitations:
The maximum length of a URL in a GET request is not defined by the HTTP specification but rather by the specific web server and the browser used to make the request. These limitations can vary widely and have evolved over time with newer versions of browsers and web servers. Here’s a general guideline based on common browser and server limitations:
- Edge: Edge has a maximum URL length of 2,083 characters. For Edge, the newer versions are based on Chromium, which generally allows longer URLs, similar to Chrome.
- Firefox: Firefox doesn’t officially document a maximum URL length, but very long URLs (over 64,000 characters) may cause issues. Practical use suggests staying under 2,000 characters to ensure compatibility.
- Chrome: Chrome has a limit of around 8,192 characters for the maximum length of a URL.
- Safari: Safari’s limit is around 80,000 characters for a URL. However, for best practices, it’s recommended to keep URLs under 2,000 characters.
- Opera: Similar to Chrome, Opera is based on the Chromium engine and has similar limitations, around 8,192 characters.
- Servers: The limitations on the server side can vary even more based on the server configuration and the HTTP server software. For example, Apache servers default to a limit of 8,192 characters, while IIS servers have a default limit of 16,384 characters.
When Should We Use HTTP GET Method in ASP.NET Core Web API?
Understanding when to use the GET method is important for building RESTful APIs that adhere to standard web conventions. Here are several scenarios where the GET method is typically used:
- Retrieving Resource Collections: Use GET to fetch a list or collection of resources. For example, retrieving all users from a database. The endpoint might look like /api/users.
- Fetching a Specific Resource: Use GET to retrieve the details of a specific resource by its identifier. For instance, you can get a user’s details using their ID in the URI, such as /api/users/123.
- Search Operations: GET is used to perform search operations where the search criteria are passed as query parameters in the URL. For example, searching for users by name might use a URL like /api/users?name=JohnDoe.
- Data Filtering, Sorting, and Pagination: When you need to filter, sort, or paginate collections, GET requests can include parameters that specify how the returned data should be manipulated. An endpoint for fetching a paginated list of users could be /api/users?page=2&limit=20.
- Fetching Related Resources: The GET method is suitable for retrieving resources related to a specific entity. For example, getting all orders for a user might use an endpoint like /api/users/123/orders.
Best Practices for Using GET Requests in ASP.NET Core Web API
- Idempotence: Ensure that GET requests are idempotent, meaning they can be made many times without changing the resource’s state. GET requests should not have side effects.
- Use Query Parameters for Optional Data: For searches, filters, and other optional data retrieval features, use query parameters rather than embedding data in the URI path.
- Cacheable Responses: Since GET requests do not modify resources, their responses are good candidates for caching to improve performance.
- HTTP Status Codes: Use appropriate HTTP status codes to indicate the outcome of a GET request, such as 200 (OK) for successful retrievals, 404 (Not Found) if a resource cannot be found, and 400 (Bad Request) for incorrect query parameters.
- Limit Data: Be cautious about returning large volumes of data in a single request. Use pagination, filtering, and limiting mechanisms to control the size of the response.
- Use Asynchronous Actions: Please prefer using asynchronous action methods for scalability, especially when dealing with I/O operations like database calls.
In the next article, I will discuss How to Implement the HTTP POST Method in ASP.NET Core Web API Application with Examples. In this article, I explain How to Implement the HTTP GET Method in ASP.NET Core Web API with Examples. I hope you enjoy this article, “How to Implement HTTP GET Method in ASP.NET Core Web API and Its Best Practices.”