-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JMAP Core server implementation #4
Comments
Here is some basic outline for the sake of discussion: JMAP Core server logic: // implements http.Handler so it could be simply attached to /.well-known/jmap endpoint on net/http server.
type Server struct {}
type SessionManager interface {
// value is the value of Authentication header field.
CheckAuth(value string) (bool, error)
Accounts(value string) (allAccts map[ID]Account, primaryAccts map[string]ID, err error)
}
type FuncHandler func(Invocation) (Invocation, error)
type CapabilityBackend struct {
Handlers map[string]FuncHandler
ArgUnmarshallers map[string]FuncArgsUnmarshal
}
func NewServer(auth SessionManager, cb ...CapabilityBackend) (Server, error) {} Here is the typical flow:
JMAP Mail, JMAP Calendar, etc implementations provide factory functions that return CapabilityBackend with handlers bound to user-provided backend (database) implementation. Here is the example of how hypothetical JMAP Todo implementation would look like (some parts are left out for brevity): // Implementation is provided by user.
type Backend interface {
Query(args *TodoQueryArgs) (*TodoQueryResp, error)
}
func NewTodoServer(be Backend) jmap.CapabilityBackend {
return jmap.CapabilityBackend {
Handlers: map[string]jmap.FuncHandler{
"Todo/query": func(i jmap.Invocation) (Invocation, error) {
resp, err := be.Query(i.Args.(*TodoQueryArgs))
return Invocation{Name: i.Name, CallID: i.Name, Args: resp}, err
},
},
Unmarshallers: map[string]jmap.FuncArgsUnmarshal{
"Todo/query": unmarshalTodoQueryArgs,
},
},
} |
Here is the example of main function implementation using interfaces proposed above: func main() {
sessionMngr := SessionThingy{} // perhaps something OAuth-based, whatever
todoBackend := TodoBackend{} // Our implementation of Todo DB.
jmapSrv := jmap.NewServer(&sessionMngr, todo.NewTodoServer(todoBackend))
http.Handle("/.well-known/jmap", &jmapSrv)
return http.ListenAndServeTLS(...);
} |
Things to consider
Below are things I believe would make library more useful.
go-jmap should avoid enforcing certain storage design and definitely must not provide storage implementation itself. I think it is best to simply translate API requests into corresponding method calls on some interface called "Backend" (see go-imap for a good example of how this could be done).
go-jmap should avoid enforcing certain authentication design and definitely must not provide authentication implementation itself. As with previous point, authentication should be implemented by calling out into user-provided interface implementation.
go-jmap should rely only on net/http for HTTP server. Use of more advanced frameworks will make it easier to violate the first point.
JMAP Core, JMAP Mail, etc implementations should be kept independent of each other for extensibility purposes. JMAP is not only about email.
The text was updated successfully, but these errors were encountered: