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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Further.Strapi.Shared" Version="0.0.8" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Further.Strapi.Shared" Version="0.0.8" />
                    
Directory.Packages.props
<PackageReference Include="Further.Strapi.Shared" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Further.Strapi.Shared --version 0.0.8
                    
#r "nuget: Further.Strapi.Shared, 0.0.8"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Further.Strapi.Shared@0.0.8
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Further.Strapi.Shared&version=0.0.8
                    
Install as a Cake Addin
#tool nuget:?package=Further.Strapi.Shared&version=0.0.8
                    
Install as a Cake Tool

Further.Strapi

Integration Tests codecov .NET ABP Framework License

Coverage Tree

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

  1. Start test Strapi:

    cd etc/strapi-integration-test
    npm install
    npm run develop
    
  2. Run 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

  1. Clone and build:

    git clone https://github.com/yinchang0626/Further.Strapi.git
    cd Further.Strapi
    dotnet restore && dotnet build
    
  2. Start test Strapi:

    cd etc/strapi-integration-test
    npm install && npm run develop
    
  3. Configure test settings: Create appsettings.test.json in the test project:

    {
      "StrapiOptions": {
        "StrapiUrl": "http://localhost:1337",
        "StrapiToken": "your-test-api-token"
      }
    }
    
  4. 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

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.

Version Downloads Last Updated
0.0.8 220 12/22/2025
0.0.7 237 10/15/2025
0.0.6 228 10/13/2025
0.0.5 169 10/11/2025
0.0.4 168 10/11/2025
0.0.3 203 10/10/2025
0.0.2 194 10/10/2025