https://github.com/juryrigcoder/storybloksharp
Dotnet implementation of Storyblok client
https://github.com/juryrigcoder/storybloksharp
csharp dotnet storyblok
Last synced: 4 months ago
JSON representation
Dotnet implementation of Storyblok client
- Host: GitHub
- URL: https://github.com/juryrigcoder/storybloksharp
- Owner: juryrigcoder
- License: mit
- Created: 2024-12-16T13:47:14.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-01-18T07:11:46.000Z (over 1 year ago)
- Last Synced: 2025-04-30T15:27:28.315Z (about 1 year ago)
- Topics: csharp, dotnet, storyblok
- Language: C#
- Homepage:
- Size: 117 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: contributing.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README
# StoryblokSharp
A modern .NET client for the Storyblok Headless CMS API. This project is a C# port of the official [storyblok-js-client](https://github.com/storyblok/storyblok-js-client), maintaining feature parity while providing a strongly-typed interface for .NET applications. It supports both Storyblok's Content Delivery API (v2) and Management API (v1).
## Rationale
As a personal project be kind! This is shared as is and is not for production.
## Acknowledgements
This project is a port of the [storyblok-js-client](https://github.com/storyblok/storyblok-js-client) JavaScript library, created and maintained by the Storyblok team ([@storyblok](https://github.com/storyblok)). We are grateful for their excellent work which serves as the foundation for this .NET implementation.
Additionally, we've included the richtext implementation of [richtext](https://github.com/storyblok/richtext) Javascript library, used to interact with the richtext components.
License: This project, like the original storyblok-js-client, is licensed under MIT.
Original Client Repository: https://github.com/storyblok/storyblok-js-client
Original Richtext Repository: https://github.com/storyblok/richtext
## Heritage
This library is based on the official [storyblok-js-client](https://github.com/storyblok/storyblok-js-client) JavaScript library and follows the same core principles and features. We've tried to carefully translated the JavaScript implementation to idiomatic C#, taking advantage of .NET's type system and modern features while maintaining compatibility with Storyblok's APIs. Key aspects we've preserved include:
- Same configuration options and initialization patterns
- Compatible caching mechanisms
- Equivalent rate limiting and retry logic
- Parallel rich text rendering capabilities
- Similar helper utilities and extension methods
## Features
- 🚀 Built for modern .NET (targets .NET 9.0)
- 💪 Strongly typed story content
- 🔄 Automatic rate limiting and retry handling
- 💾 Configurable caching
- 🔍 Rich text rendering
- 🔒 Thread-safe operations
- 📦 Available as a NuGet package
- 🔗 Dependency injection friendly
- 🏎️ Async/await support
## Also:
- 💡Support for both published and draft content
- 💡Comprehensive story querying and filtering
- 💡Rich text rendering with customizable schema
- 💡Built-in caching with memory and custom providers
- 💡Rate limiting and retry handling
- 💡Blazor component integration
- 💡Image optimization
- 💡HTML sanitization
## Installation
Install via Github packages - NuGet:
```bash
dotnet add package StoryblokSharp
```
The NuGet package is hosted in this GitHub repository's package registry.
## Story Retrieval
### Single Story
Retrieve a single story by its slug:
```csharp
// Get a published story
var story = await _client.GetStoryAsync("home", new StoryQueryParameters
{
Version = "published"
});
// Get a draft story
var draftStory = await _client.GetStoryAsync("home", new StoryQueryParameters
{
Version = "draft"
});
// Get a story in a specific language
var germanStory = await _client.GetStoryAsync("home", new StoryQueryParameters
{
Version = "published",
Language = "de"
});
```
### Multiple Stories
Retrieve multiple stories with filtering and pagination:
```csharp
// Get all published stories
var stories = await _client.GetStoriesAsync(new StoryQueryParameters
{
Version = "published",
PerPage = 10,
Page = 1
});
// Get stories with specific tags
var taggedStories = await _client.GetStoriesAsync(new StoryQueryParameters
{
WithTag = "featured",
SortBy = "created_at:desc"
});
// Get all stories (handles pagination automatically)
var allStories = await _client.GetAllAsync(
"cdn/stories",
new StoryQueryParameters
{
StartsWith = "blog/"
}
);
```
### Query Parameters
The `StoryQueryParameters` class provides various filtering and sorting options:
```csharp
var parameters = new StoryQueryParameters
{
// Version control
Version = "published", // or "draft"
// Pagination
PerPage = 10,
Page = 1,
// Filtering
StartsWith = "blog/",
WithTag = "featured",
SearchTerm = "tutorial",
ExcludingFields = "body,image",
// Sorting
SortBy = "created_at:desc",
// Language
Language = "en",
FallbackLang = "de",
// Relations
ResolveLinks = "1",
ResolveRelations = new[] { "author", "categories" },
ResolveLevel = 2
};
```
### Working with Content Types
You can create strongly-typed models for your content:
```csharp
public class BlogPost
{
public string Title { get; set; }
public string Slug { get; set; }
public RichTextField Content { get; set; }
public Asset FeaturedImage { get; set; }
public DateTime PublishedDate { get; set; }
public string[] Tags { get; set; }
}
// Use the typed model
var response = await _client.GetStoryAsync("my-blog-post");
var title = response.Story.Content.Title;
var content = response.Story.Content.Content;
```
## Basic Usage
```csharp
// Configure services
services.AddStoryblokClient(builder => builder
.WithAccessToken("your_access_token")
.WithCache(options => options
.WithType(CacheType.Memory)
.WithDefaultExpiration(TimeSpan.FromMinutes(5)))
.WithMaxRetries(3)
.WithRateLimit(5));
// Inject and use the client
public class MyService
{
private readonly IStoryblokClient _client;
public MyService(IStoryblokClient client)
{
_client = client;
}
public async Task> GetStoryAsync() where T : class
{
var parameters = new StoryQueryParameters
{
Version = "published",
Language = "en"
};
var response = await _client.GetStoryAsync("home", parameters);
return response.Story;
}
}
```
## Advanced Configuration
The client can be configured with various options:
```csharp
services.AddStoryblokClient(builder => builder
.WithAccessToken("your_access_token")
.WithOAuthToken("your_oauth_token") // For management API
.WithRegion(Region.EU)
.WithHttps()
.WithMaxRetries(3)
.WithTimeout(30)
.WithRateLimit(5)
.WithHeaders(new Dictionary
{
["Custom-Header"] = "Value"
})
.WithCache(options => options
.WithType(CacheType.Memory)
.WithDefaultExpiration(TimeSpan.FromMinutes(5)))
.WithCustomCache(new YourCustomCacheProvider())
.WithRichTextSchema(new YourCustomSchema())
.WithComponentResolver((type, props) => $"
{type}")
.WithResponseInterceptor(async response =>
{
// Custom response handling
return response;
}));
```
## Rich Text Rendering
The library includes a powerful rich text renderer with support for custom resolvers:
```csharp
services.Configure(options =>
{
options.OptimizeImages = true;
options.KeyedResolvers = true;
options.InvalidNodeHandling = InvalidNodeStrategy.Remove;
options.MarkSortPriority = new[]
{
MarkTypes.Bold,
MarkTypes.Italic,
MarkTypes.Link
};
});
```
## Blazor Integration
StoryblokSharp provides seamless integration with Blazor components:
```csharp
// Register Blazor component resolver
services.AddBlazorComponentResolver();
// Register a component
services.AddStoryblokComponent("hero");
// Create a Blazor component
public class HeroComponent : ComponentBase, IComponent
{
[Parameter]
public string Title { get; set; }
[Parameter]
public string Subtitle { get; set; }
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenElement(0, "div");
builder.AddAttribute(1, "class", "hero");
builder.OpenElement(2, "h1");
builder.AddContent(3, Title);
builder.CloseElement();
builder.OpenElement(4, "p");
builder.AddContent(5, Subtitle);
builder.CloseElement();
builder.CloseElement();
}
}
// Use in Storyblok content
@{
var story = await StoryblokClient.GetStoryAsync("home");
var component = story.Story.Content.hero;
}
```
## Image Optimization
Configure image optimization options:
```csharp
services.Configure(options =>
{
options.OptimizeImages = true;
options.ImageOptions = new ImageOptimizationOptions
{
Width = 800,
Height = 600,
Loading = "lazy",
Class = "optimized-image",
SrcSet = new[]
{
new SrcSetEntry { Width = 400 },
new SrcSetEntry { Width = 800 },
new SrcSetEntry { Width = 1200 }
},
Sizes = new[]
{
"(max-width: 400px) 100vw",
"(max-width: 800px) 50vw",
"800px"
},
Filters = new ImageFilters
{
Quality = 80,
Format = "webp",
Grayscale = false
}
}
});
```
## Security
The library includes built-in HTML sanitization:
```csharp
services.Configure(options =>
{
options.AllowedTags.Add("custom-tag");
options.AllowedAttributes["a"].Add("rel");
options.AllowedProtocols.Add("tel");
});
```
## Contributing
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Support
You can customize story queries with various parameters:
```csharp
var parameters = new StoryQueryParameters
{
Version = "draft", // 'draft' or 'published'
Language = "en", // Language code
ResolveLinks = "story", // How to resolve links
ResolveRelations = new[] { "author" },// Relations to resolve
ExcludingFields = "long_text", // Fields to exclude
Sort_by = "position:desc", // Sort order
StartsWith = "blog/", // Filter by path
WithTag = "featured", // Filter by tag
Page = 1, // Page number
PerPage = 10 // Items per page
};
var stories = await _storyblok.GetStoriesAsync(parameters);
```
## Security
The library includes built-in HTML sanitization:
```csharp
services.Configure(options =>
{
options.AllowedTags.Add("custom-tag");
options.AllowedAttributes["a"].Add("rel");
options.AllowedProtocols.Add("tel");
});
```
## Contributing
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Support
- [Documentation](https://github.com/juryrigcoder/storybloksharp/wiki)
- [Issue Tracker](https://github.com/juryrigcoder/storybloksharp/issues)
- [Storyblok API Reference](https://www.storyblok.com/docs/api/content-delivery)