Further.Strapi.Shared
0.0.8
dotnet add package Further.Strapi.Shared --version 0.0.8
NuGet\Install-Package Further.Strapi.Shared -Version 0.0.8
<PackageReference Include="Further.Strapi.Shared" Version="0.0.8" />
<PackageVersion Include="Further.Strapi.Shared" Version="0.0.8" />
<PackageReference Include="Further.Strapi.Shared" />
paket add Further.Strapi.Shared --version 0.0.8
#r "nuget: Further.Strapi.Shared, 0.0.8"
#:package Further.Strapi.Shared@0.0.8
#addin nuget:?package=Further.Strapi.Shared&version=0.0.8
#tool nuget:?package=Further.Strapi.Shared&version=0.0.8
Further.Strapi
A comprehensive .NET integration library for Strapi v5 headless CMS, built on top of the ABP Framework.
๐ Features
- ๐ Complete Strapi v5 API Integration - Collection Types, Single Types, and Components
- ๐ Media Library Support - Upload, manage, and organize media files
- ๐งฉ Polymorphic Components - Handle complex content structures with dynamic zones
- ๐ Advanced Querying - Filtering, sorting, and population with fluent Action-based API
- ๐ก๏ธ Type-Safe Operations - Strongly-typed C# interfaces for all Strapi operations
- โจ Unified API Design - Consistent Action-based configuration across all query builders
๐ Quick Start
1. Install the Package
dotnet add package Further.Strapi
2. Configure Services
Basic Configuration
[DependsOn(typeof(StrapiModule))]
public class YourAppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<StrapiOptions>(options =>
{
options.StrapiUrl = "http://localhost:1337";
options.StrapiToken = "your-api-token";
});
}
}
Advanced Configuration
[DependsOn(typeof(StrapiModule))]
public class YourAppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Method 1: Use appsettings.json
// No additional configuration needed - reads from "Strapi" section
// Method 2: Override with code
context.Services.AddStrapi(builder =>
{
builder.ConfigureOptions(options =>
{
options.StrapiUrl = "http://production-strapi.example.com";
options.StrapiToken = "production-token";
});
// Customize HttpClient behavior
builder.ConfigureHttpClient((serviceProvider, client) =>
{
client.Timeout = TimeSpan.FromSeconds(60);
client.DefaultRequestHeaders.Add("X-Custom-Header", "MyApp");
});
});
}
}
Configuration with appsettings.json
{
"Strapi": {
"StrapiUrl": "http://localhost:1337",
"StrapiToken": "your-api-token"
}
}
3. Work with Collection Types
Collection Types handle multiple content items of the same type (Articles, Products, Users).
public class ArticleService : ApplicationService
{
private readonly ICollectionTypeProvider<Article> _articleProvider;
public ArticleService(ICollectionTypeProvider<Article> articleProvider)
{
_articleProvider = articleProvider;
}
public async Task<List<Article>> GetPublishedArticlesAsync()
{
return await _articleProvider.GetListAsync(
filter: f => f
.Where("title", FilterOperator.ContainsInsensitive, "ๆ่ก")
.And("publishedAt", FilterOperator.NotNull),
populate: p => p
.Include("author")
.Include("blocks"),
sort: s => s.Descending("publishedAt"),
pagination: p => p.Page(1, 10)
);
}
public async Task<string> CreateArticleAsync(Article article)
{
return await _articleProvider.CreateAsync(article);
}
public async Task<Article> GetArticleAsync(string documentId)
{
return await _articleProvider.GetAsync(documentId);
}
}
4. Work with Single Types
Single Types handle global or unique content (Global Settings, Homepage, About Us).
public class GlobalSettingsService : ApplicationService
{
private readonly ISingleTypeProvider<GlobalSettings> _globalProvider;
public async Task<GlobalSettings> GetGlobalSettingsAsync()
{
return await _globalProvider.GetAsync();
}
public async Task UpdateGlobalSettingsAsync(GlobalSettings settings)
{
await _globalProvider.UpdateAsync(settings);
}
}
5. Work with Media Library
public class MediaService : ApplicationService
{
private readonly IMediaLibraryProvider _mediaProvider;
public async Task<StrapiMediaField> UploadFileAsync(IFormFile file)
{
var fileUpload = new FileUploadRequest
{
Files = new[] { file },
FileInfo = new[]
{
new FileInfoRequest
{
AlternativeText = "Uploaded image",
Caption = "Image caption"
}
}
};
var results = await _mediaProvider.UploadAsync(fileUpload);
return results.FirstOrDefault();
}
public async Task<List<StrapiMediaField>> GetMediaLibraryAsync()
{
return await _mediaProvider.GetLibraryAsync();
}
public async Task<StrapiMediaField> UpdateFileInfoAsync(int fileId, FileInfoRequest fileInfo)
{
return await _mediaProvider.UpdateFileInfoAsync(fileId, fileInfo);
}
}
๐งช Development & Testing
For Local Testing
Start test Strapi:
cd etc/strapi-integration-test npm install npm run developRun tests:
# Fast tests only dotnet test --filter "Category!=StrapiRealIntegration" # All tests (requires Strapi running) dotnet test
GitHub Actions Integration Tests
- Manual trigger: Use GitHub Actions UI and enable "Run integration tests"
- Commit trigger: Include
[integration]in commit message - Automatic: Integration tests run automatically in CI when triggered
๐ Advanced Usage
Complex Filtering
var articles = await _articleProvider.GetListAsync(
filter: f => f
.Where("title", FilterOperator.ContainsInsensitive, "technology")
.And(nested => nested
.Where("author.name", FilterOperator.Equals, "John Doe")
.Or("author.email", FilterOperator.Contains, "@company.com")
)
.And("publishedAt", FilterOperator.Between, startDate, endDate),
sort: s => s
.Descending("publishedAt")
.Ascending("title"),
populate: p => p
.Include("author")
.Include("categories")
.Include("dynamicZone"),
pagination: p => p
.Page(1, 20)
.WithCount(true)
);
Polymorphic Component Handling
[StrapiComponentName("shared.rich-text")]
public class RichTextComponent : IStrapiComponent
{
public string Body { get; set; } = string.Empty;
// __component is automatically handled by the polymorphic system
}
[StrapiComponentName("shared.media")]
public class MediaComponent : IStrapiComponent
{
public StrapiMediaField? File { get; set; }
// __component is automatically handled by the polymorphic system
}
// Components are automatically handled based on polymorphic serialization
var article = await _articleProvider.GetAsync(documentId,
populate: p => p.Include("dynamicZone"));
foreach (var component in article.DynamicZone)
{
// Polymorphic deserialization is handled automatically
// Type checking can be done using pattern matching
switch (component)
{
case RichTextComponent richText:
Console.WriteLine($"Rich text: {richText.Body}");
break;
case MediaComponent media:
Console.WriteLine($"Media file: {media.File.Url}");
break;
}
case nameof(RichTextComponent):
var richText = component as RichTextComponent;
Console.WriteLine($"Rich Text: {richText?.Body}");
break;
case nameof(MediaComponent):
var media = component as MediaComponent;
Console.WriteLine($"Media: {media?.File?.Name}");
break;
}
}
Multiple Pagination Modes
// Traditional page-based pagination
var pagedArticles = await _articleProvider.GetListAsync(
pagination: p => p.Page(1, 10)
);
// Offset-based pagination with performance optimization
var offsetArticles = await _articleProvider.GetListAsync(
pagination: p => p
.StartLimit(0, 20)
.WithCount(false) // Skip total count for better performance
);
๐๏ธ Architecture
Project Structure
Further.Strapi/
โโโ Further.Strapi/ # Core implementation
โ โโโ CollectionTypeProvider.cs # Collection type operations
โ โโโ SingleTypeProvider.cs # Single type operations
โ โโโ MediaLibraryProvider.cs # Media library management
โ โโโ StrapiProtocol.cs # HTTP protocol handling
โ โโโ StrapiWriteSerializer.cs # Smart serialization
โโโ Further.Strapi.Shared/ # Shared utilities and interfaces
โ โโโ IStrapiComponent.cs # Component interface
โ โโโ StrapiMediaField.cs # Media field types
โ โโโ StrapiAttributes.cs # Component name attributes
โ โโโ Components/ # Shared component definitions
โโโ Further.Strapi.Tests/ # Comprehensive test suite
โโโ Integration/ # Integration tests
โโโ Unit/ # Unit tests
โโโ Components/ # Component-specific tests
Key Components
- Providers: High-level service abstractions for different Strapi content types
- Protocol Layer: Low-level HTTP communication with Strapi API
- Serialization: Intelligent handling of Strapi-specific data structures
- Query Builders: Fluent API for building complex queries
๐ค Contributing
We welcome contributions! Please see our Contributing Guide for detailed information.
Quick Development Setup
Clone and build:
git clone https://github.com/yinchang0626/Further.Strapi.git cd Further.Strapi dotnet restore && dotnet buildStart test Strapi:
cd etc/strapi-integration-test npm install && npm run developConfigure test settings: Create
appsettings.test.jsonin the test project:{ "StrapiOptions": { "StrapiUrl": "http://localhost:1337", "StrapiToken": "your-test-api-token" } }Run tests:
dotnet test
Contribution Guidelines
- ๐ Bug Reports: Open an issue with reproduction steps
- โจ Feature Requests: Describe use cases and expected behavior
- ๐ง Pull Requests: Fork โ Code โ Test โ Document โ Submit
- ๐ Code Style: Follow C# conventions, add XML docs for public APIs
- ๐งช Testing: Write unit tests for new functionality, include integration tests for API interactions
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Support
- ๐ Documentation
- ๐ Issue Tracker
- ๐ฌ Discussions
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.5)
- Volo.Abp.Core (>= 8.3.0)
- Volo.Abp.Json.SystemTextJson (>= 8.3.0)
-
net9.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.5)
- Volo.Abp.Core (>= 9.3.5)
- Volo.Abp.Json.SystemTextJson (>= 9.3.5)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Further.Strapi.Shared:
| Package | Downloads |
|---|---|
|
Further.Strapi.Contracts
A comprehensive .NET integration library for Strapi v5 headless CMS, built on top of the ABP Framework. |
GitHub repositories
This package is not used by any popular GitHub repositories.