Restling is a lightweight and configurable REST client library for .NET. It provides typed and untyped HTTP operations, request-level and client-level headers, JSON and XML payload handling, raw and form URL-encoded requests, cookie injection and persistence, and direct access to response metadata.
Restling targets .NET 8, .NET 9, and .NET 10 and can be used by .NET for Android, .NET for iOS, and .NET MAUI applications.
- Async GET, POST, PUT, DELETE, raw, and form URL-encoded requests.
- Typed response deserialization and access to the original response content.
- Automatic JSON serializer selection, with explicit System.Text.Json or Newtonsoft.Json overrides.
- XML deserialization with external entity processing disabled by default.
- Default and per-request headers, including authentication headers.
- Custom
HttpMessageHandler, timeout, user agent, and cookie configuration. - Cookie injection and optional file-backed cookie storage.
- Response status, timing, headers, redirect location, charset, raw bytes, and exceptions.
- URI validation enabled by default, with custom validation support.
Install the Restling package.
dotnet add package RestlingInstall-Package RestlingAdd the core namespace and create a client:
usingAMDevIT.Restling.Core;RestlingClientclient=new();usingAMDevIT.Restling.Core;RestlingClientclient=new();RestRequestResult<TodoItem>result;result=awaitclient.GetAsync<TodoItem>("https://api.example.com/todos/1",cancellationToken:cancellationToken);if(result.IsSuccessful&&result.Datais not null){Console.WriteLine(result.Data.Title);}else{Console.WriteLine($"Request failed: {result.StatusCode} - {result.Exception}");}RestRequestResult<T> exposes the deserialized value through Data. It also retains the status code, elapsed time, response headers, string content, raw bytes, content type, charset, and any exception raised while executing or decoding the request.
The first generic type is the response model and the second is the request model:
CreateTodoRequestpayload=new("Read the Restling wiki",Completed:false);RestRequestResult<TodoItem>result;result=awaitclient.PostAsync<TodoItem,CreateTodoRequest>("https://api.example.com/todos",payload,cancellationToken:cancellationToken);usingAMDevIT.Restling.Core.Network;RequestHeadersheaders=new(newAuthenticationHeader("Bearer",accessToken));headers.Headers.Add("X-Correlation-ID",correlationId);RestRequestResult<TodoItem>result=awaitclient.GetAsync<TodoItem>("https://api.example.com/todos/1",headers,cancellationToken:cancellationToken);Use HttpClientContextBuilder when settings must apply to every request made by a client:
usingAMDevIT.Restling.Core;usingAMDevIT.Restling.Core.Network.Builders;HttpClientContextBuilderbuilder=new();builder.AddUserAgent("MyApp/1.0").AddDefaultHeader("X-App-Version","1.0.0").AddAuthenticationHeader("Bearer",accessToken).SetTimeout(TimeSpan.FromSeconds(30));RestlingClientclient=new(builder);You can also supply or configure an HttpMessageHandler:
HttpClientContextBuilderbuilder=new();builder.ConfigureHandler(handler =>{if(handlerisSocketsHttpHandlersocketsHandler){socketsHandler.AllowAutoRedirect=true;socketsHandler.PooledConnectionLifetime=TimeSpan.FromMinutes(5);}});RestlingClientclient=new(builder);usingAMDevIT.Restling.Core.Network;RestRawRequestrequest=new("https://api.example.com/events",AMDevIT.Restling.Core.HttpMethod.Post,content:json,contentType:HttpMediaType.ApplicationJson);RestRequestResult<ApiResponse>result=awaitclient.ExecuteRawRequestAsync<ApiResponse>(request,cancellationToken:cancellationToken);IDictionary<string,string>fields=newDictionary<string,string>{["grant_type"]="client_credentials",["scope"]="api.read"};FormUrlEncodedRequestrequest=new("https://identity.example.com/token",AMDevIT.Restling.Core.HttpMethod.Post,fields);RestRequestResult<TokenResponse>result=awaitclient.ExecuteFormUrlEncodedRequest<TokenResponse>(request,cancellationToken:cancellationToken);Restling automatically selects between Newtonsoft.Json and System.Text.Json by inspecting the model. You can set a client-wide default or override it for an individual request:
usingAMDevIT.Restling.Core.Serialization;client.SelectedDefaultSerializationLibrary=PayloadJsonSerializerLibrary.SystemTextJson;RestRequestResult<TodoItem>result=awaitclient.GetAsync<TodoItem>("https://api.example.com/todos/1",forcePayloadJsonSerializerLibrary:PayloadJsonSerializerLibrary.NewtonsoftJson,cancellationToken:cancellationToken);Inject individual cookies or a complete CookieContainer through the builder:
usingAMDevIT.Restling.Core.Cookies;usingAMDevIT.Restling.Core.Network.Builders;HttpCookieDatasessionCookie=new("session-id",sessionId,domain:"api.example.com",path:"/",isSecure:true);HttpClientContextBuilderbuilder=new();builder.AddCookie(sessionCookie);RestlingClientclient=new(builder);Restling also provides CookieStorageProvider for loading and saving cookies to a JSON file. Storage encryption is available by supplying an ICookieStorageProviderEncrypter implementation.
Restling returns a result object for HTTP failures and for most execution or decoding errors. Check IsSuccessful, then inspect StatusCode and Exception:
RestRequestResult<TodoItem>result=awaitclient.GetAsync<TodoItem>(uri,cancellationToken:cancellationToken);if(!result.IsSuccessful){Console.WriteLine(result.StatusCode);Console.WriteLine(result.Exception?.Message);Console.WriteLine(result.Content);return;}TodoItem?todo=result.Data;See the Restling GitHub Wiki for installation guidance, complete quick starts, client configuration, request types, authentication, serialization, cookies, response handling, and security notes.
The name combines "REST" and "Changeling", the Fae beings from Northern folk tales. Restling is a library that took the form of a REST client, although its journey began as something entirely different.
Restling is distributed under the MIT License.