.NET Library for ButterCMS API.
For a comprehensive list of examples, check out the API documentation.
To install ButterCMS, run the following command in the Package Manager Console
PM> Install-Package ButterCMS
The library can also be installed to the project via .NET CLI
dotnet add package ButterCMS
Or by adding the package manually to the project file
<ItemGroup>
<PackageReference Include="ButterCMS" Version="1.3.4" />
</ItemGroup>
To get started with the Butter API, instantiate the ButterCMSClient with the API key found in the Butter Admin Settings. An optional timeout parameter can be passed as a TimeSpan; the default is 10 seconds.
using ButterCMS;
...
var butterClient = new ButterCMSClient("API KEY");
If the application will be making many Butter API calls, it is recommended to store and re-use the client object.
Each Butter client method has a synchronous version and an asynchronous version. Asynchronous methods are appended with the word "Async".
Listing posts returns a PostsResponse object. This object consists of a metadata object and IEnumerable<Post>
Parameter | Default | Description |
---|---|---|
page(optional) | 1 | Used to paginate through older posts. |
pageSize(optional) | 10 | Used to set the number of blog posts shown per page. |
excludeBody(optional) | false | When true, does not return the full post body. Useful for keeping response size down when showing a list of blog posts. |
authorSlug(optional) | Filter posts by an author’s slug. | |
categorySlug(optional) | Filter posts by a category’s slug. |
PostsResponse posts = butterClient.ListPosts();
PostsResponse filteredPosts = await butterClient.ListPostsAsync(page: 2, pageSize: 5, excludeBody: true, authorSlug: "alice", categorySlug: "dot-net");
Retrieving a single Post will return a PostResponse object. This object consists of a single Post and Post Metadata. Post Metadata offers hints about the Previous and Next posts.
Parameter | Description |
---|---|
slug | The slug of the post to be retrieved. |
PostResponse controversialPost = butterClient.RetrievePost("tabs-vs-spaces-throwdown");
PostResponse safePost = await butterClient.RetrievePostAsync("puppies-and-kittens");
Searching posts will return the same object as listing posts, PostsResponse
Parameter | Default | Description |
---|---|---|
query | Search query | |
page(optional) | 1 | Used to paginate through older posts. |
pageSize(optional) | 10 | Used to set the number of blog posts shown per page. |
PostsResponse posts = butterClient.SearchPosts("spaceships");
PostsResponse caffeinePosts = await butterClient.SearchPostsAsync(query: "coffee", page: 3, pageSize: 5);
Listing Authors returns IEnumerable<Author>
Parameter | Description |
---|---|
includeRecentPosts(optional) | If true, will return the author's recent posts in the response |
IEnumerable<Author> authors = butterClient.ListAuthors();
IEnumerable<Author> authorsWithPosts = await butterClient.ListAuthorsAsync(includeRecentPosts: true);
Retrieving an author returns an Author object
Parameter | Description |
---|---|
authorSlug | The slug of the author to be retrieved. |
includeRecentPosts(optional) | If true, will return the author's recent posts in the response |
Author sally = butterClient.RetrieveAuthor("sally");
Author tylerAndPosts = await butterClient.RetrieveAuthorAsync(authorSlug: "tyler", includeRecentPosts: true);
Listing Categories returns IEnumerable<Category>
Parameter | Description |
---|---|
includeRecentPosts(optional) | If true, will return recent posts along with categories |
IEnumerable<Category> categories = butterClient.ListCategories();
IEnumerable<Category> categoriesWithPosts = await butterClient.ListCategoriesAsync(includeRecentPosts: true);
Retrieving a single category returns Category
Parameter | Description |
---|---|
categorySlug | The slug of the category to be retrieved. |
includeRecentPosts(optional) | If true, will return recent posts along with category |
Category dotnetCategory = butterClient.RetrieveCategory("dotnet");
Category fsharpCategoryWithPosts = await butterClient.RetrieveCategoryAsync(categorySlug: "fsharp", includeRecentPosts: true);
Each of the feeds methods returns an XmlDocument.
Retrieve a fully generated RSS feed for your blog.
XmlDocument rssFeed = butterClient.GetRSSFeed();
XmlDocument rssFeed = await butterClient.GetRSSFeedAsync();
Retrieve a fully generated Atom feed for your blog.
XmlDocument atomFeed = butterClient.GetAtomFeed();
XmlDocument atomFeed = await butterClient.GetAtomFeedAsync();
Retrieve a fully generated sitemap for your blog.
XmlDocument siteMap = butterClient.GetSitemap();
XmlDocument siteMap = await butterClient.GetSitemapAsync();
New in version 1.3.0
By the power of .NET generics, Content Fields can now be deserialized by the library! The former method that would defer deserialization is still available to ease transition.
Parameter | Description |
---|---|
keys | String array of desired keys |
parameterDictionary(optional) | Dictionary of additional parameters, such as "locale" or "test" |
Exception | Description |
---|---|
ContentFieldObjectMismatchException | This exception will be thrown when the library can't fit the returned data into the passed object class. |
var keys = new string[2] { "team_members[name=Elon]", "homepage_headline" };
var dict = new Dictionary<string, string>()
{
{ "locale", "de" },
{ "test", "1" }
};
var teamMembersAndHeadline = butterClient.RetrieveContentFields<TeamMembersHeadline>(keys, dict);
** Content Fields JSON documentation** :
As demonstrated in the Content Fields documentation, any number of user-defined content fields can be retrieved from the API, these can get complicated in C# and you may choose to handle the response yourself. The RetrieveContentFieldsJSON() method will return the raw JSON response from the Butter API.
Parameter | Description |
---|---|
keys | String array of desired keys |
parameterDictionary(optional) | Dictionary of additional parameters, such as "locale" and "test" |
var keys = new string[2] { "team_members[name=Elon]", "homepage_headline" };
var dict = new Dictionary<string, string>()
{
{ "locale", "de" },
{ "test", "1" }
};
var contentFields = await butterClient.RetrieveContentFieldsJSONAsync(keys, dict);
ButterCMS Pages can be retrieved by first defining the custom Page Type as a class. These custom Page Types are defined in the Butter admin.
Listing Pages returns a PagesResponse<T> object. Full API documentation can be found at https://buttercms.com/docs/api/#list-pages-for-a-page-type.
Parameter | Description |
---|---|
pageType | Desired page type |
parameterDictionary | Dictionary of additional parameters. These options are described in greater detail in the full API documentation. |
Exception | Description |
---|---|
PagesObjectMismatchException | This exception will be thrown when the library can't fit the returned data into the passed object class. |
Retrieving a single page returns a PageResponse<T> object
Parameter | Description |
---|---|
pageType | Desired page type |
pageSlug | Slug of the desired page |
parameterDictionary | Dictionary of additional parameters |
Exception | Description |
---|---|
PagesObjectMismatchException | This exception will be thrown when the library can't fit the returned data into the passed object class. |
public namespace HungryDevApp
{
public class RecipePage
{
public string category { get; set; }
public string recipe_name { get; set; }
public string main_ingredient { get; set; }
public double estimated_cooking_time_in_minutes { get; set; }
public string ingredient_list { get; set; }
public string instructions { get; set; }
}
public class RecipesController : Controller
{
[Route(recipes/)]
public virtual ActionResult Index(int page = 1, int pageSize = 10)
{
var butterClient = new ButterCMSClient("API KEY");
var parameterDict = new Dictionary<string, string>()
{
{"page", page.ToString()},
{"page_size", pageSize.ToString()}
};
PagesResponse<RecipePage> recipePages = butterClient.ListPages<RecipePage>("recipe", parameterDict);
var viewModel = new RecipesViewModel();
viewModel.PreviousPageNumber = recipePages.Meta.PreviousPage;
viewModel.NextPageNumber = recipePages.Meta.NextPage;
viewModel.PagesCount = recipePages.Meta.Count;
viewModel.Recipes = new List<RecipeViewModel>();
foreach (Page<RecipePage> recipe in recipePages.Data)
{
RecipeViewModel recipeViewModel = new RecipeViewModel();
recipeViewModel.Category = recipe.Fields.category;
recipeViewModel.RecipeName = recipe.Fields.recipe_name;
recipeViewModel.MainIngredient = recipe.Fields.main_ingredient;
recipeViewModel.EstimatedCookingTimeInMinutes = recipe.Fields.estimated_cooking_time_in_minutes;
recipeViewModel.IngredientList = recipe.Fields.ingredient_list;
recipeViewModel.Instructions = recipe.Fields.instructions;
viewModel.Recipes.Add(recipeViewModel);
}
return View(viewModel);
}
[Route(recipe/{slug})]
public virtual ActionResult Recipe(string slug)
{
var butterClient = new ButterCMSClient("API KEY");
PageResponse<RecipePage> recipe = butterClient.RetrievePage<RecipePage>("recipe", slug);
var viewModel = new RecipeViewModel();
viewModel.Category = recipe.Data.Fields.category;
viewModel.RecipeName = recipe.Data.Fields.recipe_name;
viewModel.MainIngredient = recipe.Data.Fields.main_ingredient;
viewModel.EstimatedCookingTimeInMinutes = recipe.Data.Fields.estimated_cooking_time_in_minutes;
viewModel.IngredientList = recipe.Data.Fields.ingredient_list;
viewModel.Instructions = recipe.Data.Fields.instructions;
return View(viewModel);
}
}
public class RecipesViewModel
{
public List<RecipeViewModel> Recipes { get; set; }
public int? PreviousPageNumber { get; set; }
public int? NextPageNumber { get; set; }
public int PagesCount { get; set; }
}
public class RecipeViewModel
{
public string Category { get; set; }
public string RecipeName { get; set; }
public string MainIngredient { get; set; }
public double EstimatedCookingTimeInMinutes { get; set; }
public string IngredientList { get; set; }
public string Instructions { get; set; }
}
}
@using HungryDevApp
@{
Layout = "~/Views/Shared/Layouts/_Layout.cshtml";
}
@model RecipesViewModel
<div>
<a href="/recipes/?page=@{Model.PreviousPageNumber}&pageSize=10">Previous page</a>
<a href="/recipes/?page=@{Model.NextPageNumber}&pageSize=10">Next page</a>
</div>
<div>
<p>@{Model.PagesCount} recipes total</p>
</div>
<div>
<ul>
@foreach(var page in Model.Recipes)
{
<li>
<a href="/recipe/@{page.Slug}">@{page.RecipeName}
</li>
}
</ul>
</div>
@using HungryDevApp
@{
Layout = "~/Views/Shared/Layouts/_Layout.cshtml";
}
@model RecipeViewModel
<div>
<h2>@{Model.RecipeName}</h2>
<p>Estimated cooking time: @{Model.EstimatedCookingTimeInMinutes} minutes</p>
<h3>Ingredients:</h3>
<p>@{Model.IngredientList}</p>
<h3>Instructions:</h3>
<p>@{Model.Instructions}</p>
</div>
Property | Type |
---|---|
Meta | PostsMeta |
Data | IEnumerable<Post> |
Property | Type |
---|---|
Count | int |
NextPage | int? |
PreviousPage | int? |
Property | Type |
---|---|
Url | string |
Created | DateTime |
Published | DateTime |
Author | Author |
Categories | IEnumerable<Category> |
FeaturedImage | string |
Slug | string |
Title | string |
Body | string |
Summary | string |
SeoTitle | string |
MetaDescription | string |
Status | PostStatusEnum |
Constant | Value |
---|---|
Unknown | 0 |
Draft | 1 |
Published | 2 |
Property | Type |
---|---|
Meta | PostMeta |
Data | Post |
Property | Type |
---|---|
NextPost | PostLight |
PreviousPost | PostLight |
Property | Type |
---|---|
Slug | string |
Title | string |
FeaturedImage | string |
Property | Type |
---|---|
FirstName | string |
LastName | string |
string | |
Slug | string |
Bio | string |
Title | string |
LinkedinUrl | string |
FacebookUrl | string |
InstagramUrl | string |
PinterestUrl | string |
TwitterHandle | string |
ProfileImage | string |
RecentPosts | IEnumerable<Post> |
Property | Type |
---|---|
Name | string |
Slug | string |
RecentPosts | IEnumerable<Post> |
Property | Type |
---|---|
Meta | PageMeta |
Data | IEnumerable<Page<T>> |
Property | Type |
---|---|
Count | int |
PreviousPage | int? |
NextPage | int? |
Property | Type |
---|---|
Data | Page<T> |
Property | Type |
---|---|
Slug | string |
Fields | T |
The library throws this exception when the Butter API key used to instatiate the client was not valid.
This exception will be thrown when the library can't fit the returned data from a Content Field request into the passed object class.
This exception will be thrown when the library can't fit the returned data from a Pages request into the passed object class.