<div dir="ltr"><div>I don&#39;t know to what degree I&#39;m preaching to the choir, but I was encouraged by an acquaintance on the Swift team to put my thoughts out there whether or not I drop the mic and step away afterwards. So:</div><div><br></div><div>I&#39;ve used a couple of networking/server/web frameworks over the years, and the one that stands out for me is Netty. Netty is a highly asynchronous Java framework used in very high-performance applications (including hedge funds and Wall Stree, for example).</div><div><br></div><div>==aside==</div><div>I&#39;ve looked at: Jersey (JAX-RS), JSR 356, Wangle (Facebook&#39;s Netty-ish C++ framework that only really runs on Linux), Finagle (Twitter&#39;s Scala layer on top of Netty), writing my own with POSIX sockets + libdispatch, and writing my own with CFSockets (once each in ObjC and Swift). I also wrote my own client-side networking framework at a previous job, modeling it very roughly after the client bits of Netty (the product for which it was implemented was never released however).</div><div><br></div><div>So, while I don&#39;t think I am the most qualified to suggest what a server API&#39;s final form might look like (i&#39;ve personally dabbled a bunch but I&#39;ve invested more heavily in client-side programming than server-side), I have a couple of thoughts from an API consumer&#39;s side of things.</div><div>==end aside==</div><div><br></div><div>The common thread I&#39;ve found to help with stability and reduce code churn is the composability of layers of the stack. At a high level, the pattern I found most useful was channels and pipelines. A pipeline would have a chain of handlers to control the flow of data, and a channel would have the specific instantiation of input-&gt;handler-&gt;handler-&gt;output. For example, here&#39;s a sample pipeline:</div><div><br></div><div>==extended example==</div><div><br></div><div>* bitstream OR packet stream input (i.e. data sourced from disk, from network, from a socket, or whatever)</div><div>* Frame Decoder, which buffers the bytes until a successful decode</div><div>* Text Decoder: decodes the frame into text. This is an example, but it could otherwise some higher level message, could be some encoding other than UTF8, Maybe it&#39;s a tightly packed set of bytes, maybe it&#39;s text</div><div>* JSON Decoder: parses JSON. Maybe it even goes directly to creating structs, or maybe it creates a dictionary and passes it to...</div><div>* Model Decoder: inspects the dictionary and decides how to turn that into an object or struct.</div><div>* Application logic</div><div>* Custom error handler (each handler decides if it can handle the message passed down each stage, and errors can pass through or perhaps a previous stage can be retried, with some context dictionary of metadata to track previous failed attempts)</div><div>* Callback for output so that stateful things can be updated</div><div><br></div><div>Caching handlers would be insertable at will to bypass some pipeline stages; statefulness would be possible to encapsulate within a given stage, but by and large statefulness would express itself as a context parameter rather than the handlers being stateful themselves. Clients would prefer the above pipeline; servers would continue on to construct responses and return, and none of these stages would be required to be run synchronously (but pipeline allowing, they can) or on the same queue (they could draw on thread/queue pools as executors).</div><div><br></div><div>Maybe the wire format changes from JSON to XML or to MessagePack or whatever, but otherwise stays the same – swap that layer out. Maybe the model framework changes from hand-rolled to autogenerated, or maybe an app developer changed from an Objective-C model framework like Mantle to a Swift one – swap that layer out. Maybe the developer created an authentication layer that they insert for specific API calls that augments the context metadata so API calls further down the pipeline can make use of them (and maybe they support multiple concurrent users so they don&#39;t want to initialize the handlers with auth data). And so on.</div><div><br></div><div>==end extended example==<br></div><div><br></div><div>This pattern has worked for me on servers, as well as on an iOS app (I managed to get 0 frame drops in a very layout, network, and image-heavy app with the approach, with transparent caching and guarantees of thread safety), and from what I have seen, works also for API proxies, i.e. Thrift-to-HTTP, or vice-versa, or protobuf, or whatever format you throw a decoder or encoder on for.</div><div><br></div><div>So, that&#39;s a lot of background. Here&#39;s the TL;DR of my suggestions for the network/server APIs:</div><div><br></div><div>1) Please highly prioritize composability. A good abstraction will allow components to be composed upfront rather than creating sloppy asynchronous calls that are very difficult to trace or debug.<br></div><div>2) Please heavily isolate state; or statelessness where reasonable.</div><div>3) It might spend some extra cycles, but being asynchronous (beyond just nonblocking I/O) typically works better for apps and non-CPU-bound servers – I think CPU-heavy synchronous workloads will tend to write their own framework from low-level primitives anyways), so please build it around that.</div><div><br></div><div>So, that&#39;s it for the lower-level server stuff. For the higher-level server stuff, Dropwizard is a batteries-included framework (and the batteries are good) that incorporates Jersey, and is an opinionated and incredibly fun web/API framework. Dropwizard was built by Yammer, and has a number of good ideas built in on top of the straightforward way of creating server endpoints with it. The downside is that I didn&#39;t see anything like Jersey which did an especially good job supporting WebSockets.</div><div><br></div><div>Hope you can take inspiration from those (Netty and Dropwizard) when creating the Server APIs. I look forward to it!</div><div><br></div><div>Thanks,</div><div>Andy</div></div>