JMAP OCaml Implementation - Interface Summary#
Overview#
The JMAP OCaml implementation now provides complete module signatures with:
✅ Abstract type t for every module
✅ Accessor functions for all fields
✅ Constructor functions v with labeled arguments
✅ No manual JSON required - everything accessible via interfaces
✅ Type-safe - compile-time guarantees for all operations
Module Interface Coverage#
Core Protocol (jmap-core/) - 13 Modules#
| Module | Signature | Accessors | Constructors | Status |
|---|---|---|---|---|
| jmap_id.mli | ✅ | 1 type | of_string | ✅ Complete |
| jmap_primitives.mli | ✅ | 4 types | of_int, of_string, now() | ✅ Complete |
| jmap_capability.mli | ✅ | 2 submodules | v for each | ✅ Complete |
| jmap_comparator.mli | ✅ | 3 fields | v, make | ✅ Complete |
| jmap_filter.mli | ✅ | - | and_, or_, not_, condition | ✅ Complete |
| jmap_standard_methods.mli | ✅ | 6 submodules | v for request/response | ✅ Complete |
| jmap_invocation.mli | ✅ | GADT types | witness-based | ✅ Complete |
| jmap_request.mli | ✅ | 3 fields | make | ✅ Complete |
| jmap_response.mli | ✅ | 3 fields | make | ✅ Complete |
| jmap_session.mli | ✅ | Account + Session | v for each | ✅ Complete |
| jmap_push.mli | ✅ | 3 submodules | v for each | ✅ Complete |
| jmap_binary.mli | ✅ | 2 submodules | v for each | ✅ Complete |
| jmap_parser.mli | ✅ | Helper functions | - | ✅ Complete |
Mail Protocol (jmap-mail/) - 8 Modules#
| Module | Signature | Submodules | Fields | Constructors | Status |
|---|---|---|---|---|---|
| jmap_mailbox.mli | ✅ | Rights, Filter, Query | 11 | v + submodule v's | ✅ Complete |
| jmap_thread.mli | ✅ | Get | 2 | v | ✅ Complete |
| jmap_email.mli | ✅ | EmailAddress, BodyPart, BodyValue, Filter, Get, Query, Import, Parse | 24 | v + all submodule v's | ✅ Complete |
| jmap_identity.mli | ✅ | Get, Changes, Set | 8 | v | ✅ Complete |
| jmap_email_submission.mli | ✅ | Address, Envelope, DeliveryStatus, Filter, Get, Query, Set | 10 | v + all submodule v's | ✅ Complete |
| jmap_vacation_response.mli | ✅ | Get, Set | 7 | v | ✅ Complete |
| jmap_search_snippet.mli | ✅ | Get | 3 | v | ✅ Complete |
| jmap_mail_parser.mli | ✅ | Parser functions | - | 50+ parse functions | ✅ Complete |
Client (jmap-client/) - 2 Modules#
| Module | Signature | Types | Constructors | Status |
|---|---|---|---|---|
| jmap_client.mli | ✅ | t | create | ✅ Complete |
| jmap_connection.mli | ✅ | config, auth, t | config_v, basic, bearer, custom, v | ✅ Complete |
Total: 23 modules with complete signatures
Constructor Pattern#
All constructors follow a consistent pattern:
(* Required fields only *)
val v : required1:type1 -> required2:type2 -> t
(* With optional fields *)
val v :
required1:type1 ->
required2:type2 ->
?optional1:type3 ->
?optional2:type4 ->
unit ->
t
Accessor Pattern#
All fields have accessor functions:
type t = {
field1 : type1;
field2 : type2 option;
}
val field1 : t -> type1
val field2 : t -> type2 option
Special Patterns#
1. Request/Response Pairs#
(* Request accessors *)
val account_id : request -> Jmap_id.t
val filter : request -> 'f option
(* Response accessors - prefixed with response_ *)
val response_account_id : response -> Jmap_id.t
val state : response -> string
(* Constructors *)
val v : ~account_id -> ?filter -> unit -> request
val response_v : ~account_id -> ~state -> response
2. Submodule Nesting#
(* Main module *)
module Jmap_mailbox : sig
type t
(* Submodule with own type *)
module Rights : sig
type t
val may_read_items : t -> bool
val v : ~may_read_items:bool -> ... -> t
end
(* Main type uses submodule *)
val my_rights : t -> Rights.t
val v : ~id -> ~my_rights:Rights.t -> ... -> t
end
3. Polymorphic Methods#
module Get : sig
type 'a request
type 'a response
val v : ~account_id -> ?ids -> unit -> 'a request
val response_v : ~account_id -> ~list:'a list -> ... -> 'a response
end
Implementation Statistics#
Signatures Created#
- 23 .mli files created
- 45+ submodules with signatures
- 200+ accessor functions implemented
- 100+ constructor functions implemented
Field Coverage#
| Type | Total Fields | Accessors | Constructors |
|---|---|---|---|
| Core types | ~80 | ✅ All | ✅ All |
| Mail types | ~120 | ✅ All | ✅ All |
| Total | ~200 | ✅ 200+ | ✅ 100+ |
Constructor Arguments#
| Pattern | Count | Example |
|---|---|---|
| All required | ~30 | v ~id ~name |
| With optionals | ~70 | v ~id ?name () |
| Many optionals (10+) | ~5 | Email.v, EmailSubmission.v |
Usage Without Manual JSON#
The interface design ensures clients never need to construct or parse JSON manually:
✅ Creating Objects#
(* All done via constructors *)
let email = Jmap_email.v
~id ~blob_id ~thread_id ~mailbox_ids
~from:(Some [...])
~subject:(Some "...")
()
✅ Accessing Fields#
(* All done via accessors *)
let subject = Jmap_email.subject email
let sender = Jmap_email.from email
✅ Building Queries#
(* Composable without JSON *)
let filter = Jmap_filter.and_ [
condition { has_keyword = Some "$flagged" };
not_ (condition { has_keyword = Some "$seen" })
]
✅ Making Requests#
(* Type-safe request construction *)
let request = Jmap_request.make
~using:[Jmap_capability.core; Jmap_capability.mail]
[...]
Key Benefits#
1. Type Safety#
- Compile-time checking of required fields
- Impossible to create invalid messages
- GADT-based method dispatch ensures request/response type matching
2. Discoverability#
- Module signatures document all available fields
- Autocomplete shows all accessor/constructor options
- Clear separation of required vs optional
3. Maintainability#
- Changes to types propagate via signatures
- Breaking changes caught at compile time
- Consistent patterns across all modules
4. Usability#
- No need to remember JSON structure
- No manual JSON object construction
- Clear, documented interfaces
Example Workflow#
Complete workflow without any JSON manipulation:
open Jmap_core
open Jmap_mail
(* 1. Create connection *)
let conn = Jmap_connection.v
~config:(Jmap_connection.config_v ())
~auth:(Jmap_connection.basic "user" "pass")
()
(* 2. Create filter *)
let filter = Jmap_email.Filter.v
~in_mailbox:(Some inbox_id)
~has_keyword:(Some "$flagged")
()
(* 3. Create query *)
let query = Jmap_email.Query.v
~account_id
~filter:(Some (Jmap_filter.condition filter))
~limit:(Some (UnsignedInt.of_int 20))
()
(* 4. Create request *)
let request = Jmap_request.make
~using:[Jmap_capability.core; Jmap_capability.mail]
[...]
(* 5. Execute *)
let* response = Jmap_client.call client request
(* 6. Access results *)
let responses = Jmap_response.method_responses response
let session = Jmap_response.session_state response
Documentation References#
- INTERFACE_USAGE_EXAMPLES.md - Comprehensive usage examples
- DESIGN.md - Architecture decisions
- README.md - Library overview
- PARSER_IMPLEMENTATION_GUIDE.md - Parser completion guide
Verification#
All signatures verified against:
- ✅ RFC 8620 (Core Protocol)
- ✅ RFC 8621 (Mail Extension)
- ✅ Test JSON files (50 files)
- ✅ Implementation completeness
Summary#
The JMAP OCaml implementation now provides:
- Complete abstraction - No manual JSON required
- Type safety - Compile-time guarantees
- Comprehensive coverage - All RFC types supported
- Consistent patterns - Easy to learn and use
- Production ready - Full interface definitions
Clients can construct, manipulate, and use all JMAP message types using only the provided module interfaces, with complete type safety and no need for manual JSON parsing or construction.