Thank you for your interest in contributing to ApiSports SDK.
This project values clarity, predictability, and long-term maintainability over short-term convenience. Before contributing, please read this document carefully.
If a change conflicts with the principles described here, it is unlikely to be accepted.
Contributions must respect the following non-negotiable principles:
- AOT-first design
- No external dependencies
- Explicit APIs
- No hidden magic
- Predictable behavior over convenience
These principles are more important than feature completeness.
This SDK is designed to work with NativeAOT, not around it.
As a contributor, you must ensure that your changes:
- do not rely on reflection-based behavior
- do not introduce runtime type discovery
- do not depend on implicit serialization metadata
- do not add fallback paths that behave differently under JIT vs AOT
If a feature only works under JIT, it is considered broken.
- Only System.Text.Json source generation is allowed
- Every response root type must be explicitly registered in a
JsonSerializerContext - No shared or global “mega-contexts”
- No reflection-based serialization
- Custom converters are discouraged and must be justified
If a type is missing from the context, the correct behavior is to fail early, not to recover silently.
When adding or modifying public APIs:
- Prefer explicit types over convenience overloads
- Avoid long parameter lists
- Use query objects for endpoint parameters
- Express optionality via nullability
- Use
requiredfor parameters that are mandatory per API semantics
Do not expose:
JsonTypeInfo- serializer internals
- HTTP infrastructure details
All endpoints must use strongly typed query objects:
- One query object per endpoint (or per closely related endpoints)
- Implement
IQueryString - Explicitly map properties to query string keys
- Control formatting explicitly (dates, booleans, numbers)
Query objects must not:
- perform validation logic
- enforce cross-field constraints
- hide API behavior
They model the API — they do not “fix” it.
The client hierarchy is intentional and must be preserved:
ApiSportsSdk→ sport clients (e.g.FootballClient) → domain clients (Fixtures, Teams, Players, …)
Rules:
- Sport clients are pure aggregators
- Domain clients group related endpoints
- One method per endpoint
- No “god clients” with unrelated methods
If adding a new endpoint makes an existing client grow uncomfortably, the structure should be revisited.
When adding support for a new endpoint:
- Identify the correct domain client
- Create or extend a query object
- Add a single method mapping to the endpoint
- Register the response root type in the domain’s
JsonSerializerContext - Ensure NativeAOT publish succeeds
Avoid adding multiple endpoints in a single method.
If response DTOs already exist, reuse them.
If they do not exist:
- Create minimal, honest DTOs
- Use
public get; init; - Use explicit nullability
- Do not invent schemas not present in the API documentation
Placeholders are acceptable when the API spec does not define response bodies.
Do not introduce:
- silent error swallowing
- automatic retries
- implicit fallback behavior
Errors should:
- surface early
- include context
- be handled by the caller
Retry and throttling strategies belong to application code, not the SDK.
- Follow existing naming and file layout
- Use explicit types where the type is not obvious
- Keep classes small and focused
- Avoid clever abstractions
If code requires explanation to justify its existence, it is probably too complex.
If applicable:
- update or add sample usage
- ensure sample projects still publish under NativeAOT
- avoid tests that depend on runtime reflection
Before submitting a PR:
- Ensure the project builds
- Ensure NativeAOT publish succeeds
- Re-read this document
A PR may be rejected if it:
- introduces hidden magic
- weakens AOT guarantees
- increases surface complexity without strong justification
This is not personal — it is architectural consistency.
This project values discipline over speed.
Small, well-reasoned contributions are preferred over large feature dumps. When in doubt, open an issue to discuss design before writing code.
Thank you for helping keep the SDK clean, explicit, and boring in the best possible way.