A comprehensive .NET 10 client library for the UK Government's Legislation API (legislation.gov.uk), following the proven patterns from the Uk.Parliament project. This library will provide 100% API coverage with full type safety, resilience, and extensive testing.
Phase 1: Foundation & Core Setup - ✅ COMPLETE
Phase 2: Core Legislation API - ✅ COMPLETE
Phase 3: Type Safety with Enums - ✅ COMPLETE
Phase 4+: Planned - Ready to begin
- ✅ Full project structure with xUnit 3 testing
- ✅ XML/Atom feed parsing (API uses XML, not JSON)
- ✅ Live API integration verified
- ✅ Type-safe enum-based API (LegislationType)
- ✅ 26 tests passing, 1 skipped (documented limitation)
- ✅ Comprehensive documentation (API_ENDPOINTS.md, README.md)
- ✅ DI/IoC support with Polly resilience
- ✅ All 37 legislation types enumerated with conversion utilities
- ✅ Phase 3 Complete: Type-safe enum API implemented
- ✅ LegislationTypeExtensions: ToUriCode(), FromUriCode(), TryFromUriCode()
- ✅ Custom Refit Formatter: Automatic enum-to-string URL conversion
- ✅ All Tests Updated: Using enums instead of string literals
- ✅ 5 New Tests: Extension method validation (27 total tests)
- ✅ README Rewrite: Comprehensive enum-based examples
- 100% API Coverage: Support all legislation.gov.uk API endpoints and features
- Type Safety: Leverage Refit for compile-time type-safe REST API access
- Resilience: Implement Polly-based retry and circuit breaker policies
- Testability: Comprehensive unit and integration test coverage using xUnit 3
- Best Practices: Follow .NET coding standards, dependency injection patterns, and async/await
- Documentation: XML documentation for all public APIs
- NuGet Ready: Package metadata, versioning, and release automation
- .NET 10 (latest LTS)
- C# 14.0 with nullable reference types enabled
- Refit 8.x for type-safe HTTP API clients
- System.ServiceModel.Syndication for Atom feed parsing
- Microsoft.Extensions.DependencyInjection for IoC/DI support
- Polly for resilience and transient-fault-handling
- xUnit 3.x - Testing framework (using xunit.v3 package)
- AwesomeAssertions - Fluent assertion library (NOT FluentAssertions)
- AwesomeAssertions.Analyzers - Compile-time assertion validation
- Moq 4.x - Mocking framework for unit tests
- Coverlet - Code coverage analysis
- Nerdbank.GitVersioning - Automated semantic versioning
- Microsoft.SourceLink.GitHub - Source code debugging support
- EditorConfig - Consistent code style enforcement
Based on the developer documentation at https://www.legislation.gov.uk/developer/contents:
All 37 types enumerated in LegislationType enum:
- UK Public General Acts (ukpga)
- UK Local Acts (ukla)
- UK Private and Personal Acts (ukppa)
- Acts of the Scottish Parliament (asp)
- Acts of Senedd Cymru (asc)
- Measures of the National Assembly for Wales (mwa)
- Church Measures (ukcm)
- Acts of the Northern Ireland Assembly (nia)
- UK Statutory Instruments (uksi)
- Wales Statutory Instruments (wsi)
- Scottish Statutory Instruments (ssi)
- Northern Ireland Statutory Rules (nisr)
- Church Instruments (ukci)
- UK Ministerial Directions (ukmd)
- UK Ministerial Orders (ukmo)
- European Union Regulations (eur)
- European Union Decisions (eudn)
- European Union Directives (eudr)
- Draft Legislation (ukdsi, sdsi, nidsr)
- Impact Assessments (ukia)
- And more historical types...
- Get legislation by URI (e.g.,
/ukpga/2020/1/data.xml) - Get legislation metadata (via XML parsing)
- Get Table of Contents (
/contents/data.xml) Get specific sections/schedules/articles(Not available in API)- Get provisions at specific dates (point-in-time) (
/{date}/data.xml) - Get extent information (in XML metadata)
- Full-text search across all legislation
- Filter by:
- Type (primary/secondary/EU-origin/draft/impact assessments)
- Year/year range
- Number
- Title keywords
- Modified/enacted date ranges
- Geographical extent
- Subject matter
- Pagination support
- Sort options
- Type-specific feeds (
/{type}/data.feed) - Year-specific feeds (
/{type}/{year}/data.feed) - Parsed to
PagedResponse<LegislationItem>
- HTML - Human-readable web format ✅ Supported
- XML - Structured legislation markup (CLML) ✅ Primary format
- Atom - Feed format for updates ✅ Implemented
- RDF/Turtle/N3 - Linked data formats ⏳ Planned
JSON- Not supported by API- PDF - Document format (where available) ⏳ Planned
Pattern: /{type}/{year}/{number}[/{date}][/data.{format}]
Examples:
/ukpga/2020/1/data.xml- UK Public General Act 2020 No. 1/ukpga/2020/1/2021-01-01/data.xml- Point-in-time version/ukpga/2020/1/contents/data.xml- Table of contents/ukpga/2020/1/enacted/data.xml- As-enacted version/ukpga/1998/data.feed- Atom feed for year
- Access legislation as originally enacted
- Access current (revised) version
- Access version at any specific date
- Track amendments and changes
- England, Wales, Scotland, Northern Ireland
- Extent information per provision
- Territorial application queries
- What legislation affects this item
- What this legislation affects
- Amendment tracking
- Commencement information
- View all changes over time
- Filter by change type (amendment, repeal, substitution)
- Change metadata
Uk.Legislation/
├── .editorconfig # Code style rules ✅
├── .gitignore
├── README.md # ✅
├── MASTER_PLAN.md # This file ✅
├── API_ENDPOINTS.md # API documentation ✅
├── version.json # Nerdbank.GitVersioning ✅
├── Uk.Legislation.sln
│
├── Uk.Legislation/ # Main library project
│ ├── Uk.Legislation.csproj # ✅
│ ├── Icon.png # ✅
│ │
│ ├── Models/ # Data models
│ │ ├── Common/
│ │ │ ├── LegislationType.cs # ✅ All 37 types
│ │ │ ├── GeographicalExtent.cs # ✅
│ │ │ └── PagedResponse.cs # ✅
│ │ │
│ │ └── Legislation/
│ │ ├── LegislationItem.cs # ✅
│ │ ├── LegislationMetadata.cs # ✅
│ │ ├── TableOfContents.cs # ✅
│ │ └── Provision.cs # ✅
│ │
│ ├── Interfaces/ # API contracts
│ │ └── ILegislationApi.cs # ✅ 9 methods
│ │
│ ├── LegislationClient.cs # ✅ Main client
│ ├── LegislationClientOptions.cs # ✅ Configuration
│ │
│ ├── Extensions/ # Extension methods
│ │ ├── ServiceCollectionExtensions.cs # ✅ DI support
│ │ ├── AtomFeedExtensions.cs # ✅ Atom parsing
│ │ └── LegislationApiExtensions.cs # ✅ Typed access
│ │
│ └── Exceptions/ # Custom exceptions
│ ├── LegislationApiException.cs # ✅
│ ├── LegislationNotFoundException.cs # ✅
│ ├── InvalidLegislationUriException.cs # ✅
│ └── HttpStatusResponseException.cs # ✅
│
├── Uk.Legislation.Test/ # Test project
│ ├── Uk.Legislation.Test.csproj # ✅
│ │
│ ├── UnitTests/
│ │ └── LegislationApiUnitTests.cs # ✅ 9 tests
│ │
│ └── IntegrationTests/
│ ├── IntegrationTestBase.cs # ✅
│ └── LegislationIntegrationTests.cs # ✅ 12 tests
│
└── Uk.Legislation.NuGet/ # NuGet packaging
└── Uk.Legislation.NuGet.csproj # ✅
Status: All objectives achieved
✅ Project Structure
- Created solution with main library project
- Created test project with xUnit 3 (using xunit.v3 package)
- Created NuGet packaging project
- Set up .editorconfig (copied from Uk.Parliament)
- Configured Nerdbank.GitVersioning (v10.0)
✅ Core Dependencies
- Added Refit 8.0.0 and Refit.HttpClientFactory
- Added Microsoft.Extensions.Http 9.0.0 and Polly
- Added System.ServiceModel.Syndication 10.0.0 for Atom feeds
- Added test dependencies (xUnit 3.2.0, AwesomeAssertions 9.3.0, Moq 4.20.72)
- Configured package metadata in .csproj
✅ Base Infrastructure
- Implemented LegislationClientOptions with full configuration
- Implemented base exception types (4 exceptions)
- Created ServiceCollectionExtensions for DI (with and without resilience)
- Set up XML documentation generation
Status: All objectives achieved + API format discovery
✅ Models - Basic
- LegislationType enum (37 types with Description attributes)
- LegislationFormat enum (Json, Xml, Html, Rdf, Pdf)
- GeographicalExtent flags enum
- LegislationItem (complete model)
- LegislationMetadata (complete model)
- TableOfContents + TocItem (hierarchical structure)
- Provision (content model)
- PagedResponse (generic pagination)
✅ API Interface - XML/Atom Based
- ILegislationApi with 9 methods:
- GetLegislationXmlAsync
- GetLegislationAtDateXmlAsync
- GetLegislationAsEnactedXmlAsync
- GetProvisionXmlAsync (API limitation - returns 404)
- GetTableOfContentsXmlAsync
- GetLegislationByTypeFeedAsync
- GetLegislationByTypeAndYearFeedAsync
- GetLegislationHtmlAsync
✅ Client Implementation
- LegislationClient with both constructor patterns
- HttpClient configuration with proper headers
- Refit integration for string responses
- Error handling via exceptions
✅ Extension Methods
- AtomFeedExtensions for parsing Atom feeds
- LegislationApiExtensions for typed access
- Proper handling of legislation.gov.uk namespaces
✅ Unit Tests (9 tests - all passing)
- Mock-based tests for each API method
- Constructor pattern tests
- Atom feed parsing tests
✅ Integration Tests (12 tests - 11 passing, 1 skipped)
- Live API tests for basic retrieval
- Tested with Human Rights Act 1998, Freedom of Information Act 2000
- Verified XML, Atom feed, and HTML responses
- Point-in-time version tests
- Known limitation documented (provision endpoints)
Status: All objectives achieved - Production ready
✅ Extension Methods
- Created LegislationTypeExtensions class
- ToUriCode() - Convert enum to URI string ("ukpga")
- FromUriCode() - Convert URI string to enum
- TryFromUriCode() - Safe conversion with out parameter
✅ Refit Integration
- Created LegislationTypeUrlParameterFormatter
- Automatic enum-to-string conversion in URLs
- Integrated into RefitSettings
✅ API Updates
- Updated ILegislationApi to use LegislationType enum (9 methods)
- Updated LegislationApiExtensions to use enums
- Zero breaking changes to public API surface
✅ Testing
- Updated all 9 unit tests to use enums
- Updated all 12 integration tests to use enums
- Added 5 new tests for extension methods
- Total: 27 tests (26 passing, 1 skipped)
✅ Documentation
- README.md completely rewritten with enum examples
- All 37 legislation types documented
- Type conversion utilities documented
- Current status and working features listed
Benefits Delivered:
- 🔒 Compile-time safety (no string typos possible)
- 💡 IntelliSense support (all 37 types discoverable)
- 📖 Self-documenting code
- 🔄 Bidirectional enum ↔ string conversion
Goal: Full CLML (Crown Legislation Markup Language) parsing
-
CLML Parser
- Parse full XML structure
- Extract all metadata fields
- Parse document hierarchy (parts, chapters, sections)
- Extract provision content with formatting
-
Models Enhancement
- Add detailed CLML-specific properties
- Support for all XML elements
- Preserve formatting and structure
-
Tests
- Unit tests with sample CLML documents
- Integration tests verifying full parsing
- Point-in-Time & Versions (partially done)
- Feeds API (done via Atom)
- Changes & Amendments
- Effects & Impacts
- Geographical Extent (model done, parsing needed)
- Advanced Features
- Types & Metadata API
- Resilience & Error Handling (partially done)
- Documentation & Examples
- Performance & Optimization
- NuGet Package & Release
Document Version: 3.0
Last Updated: January 2025
Status: Phase 3 Complete - Type-Safe Enum API Production Ready
Current Progress: 3 of 14 phases complete (21%)
Test Results: 26/27 passing (96% success rate)
Next Steps:
Implement type-safe enum usage✅ Complete (Phase 3)- Begin Phase 4 - Enhanced CLML XML parsing for full metadata extraction
- Implement search API with type-safe filters