Contract first,
session types later
Marco Borst
::
vlsi -> java -> scala
Slava Schmidt
Play-Swagger plugin
@
Play-Swagger plugin
API-First single source of truth
code generation framework
=>
Specification
URLs
Verbs
Parameters
Security
Definitions Validations
Model
Test Data
Validations
Play Routes
Marshallers
Tests
Controllers
Security
Richardson Maturity Model
Level 0 - Wild Wild Web
Level 1 - Resources
Level 2 - HTTP Verbs
Level 3 - Hypermedia Controls
Level 2
of Richardson Maturity Model
Level 3
HATEOAS (Hypertext As The Engine Of Application State)
Specification
URLs
Verbs
Parameters
Definitions Mime-Types
Hypermedia
Controls
Server
Mime-Types
Hypermedia
Controls Client
Code
Client
Mime-Types
Hypermedia
Controls
Rules
Specification
Swagger RAML Apiary Blueprint
Spec formats
Swagger RAML Apiary Blueprint
Spec formats
Level 2 capable
Stateless REST communication
but
Stateful Resources
Stateful Clients
Stateful Sessions
Interacting state machines
Time
The arrows form a contract
between the server and its clients
Misbehaving state machines
Time
How to ensure right behaviour?
UBF - “who checks what goes over the wire”
UBF contract checker
Contract checker
CC
RS
AS
RS’
AS
RS’
AS’
S{HC} HC
HATEOAS
only allows us to check the
client behaviour
For the server we need
additional information
State
transitions
x-api-first-transitions:
packaged:
sending:
condition: Post is open
self:
sending:
moving:
condition: Accepted at the post
self:
moving:
delivering:
condition: Receiver is at home
lost:
self:
destroyed:
delivering:
delivered:
condition: Package undamaged
self:
lost:
moving:
State
transitions
UBF Session State
HATEOAS - State Locations
Contract checker
CC CC
RS
AS
RS’
AS
RS’
AS’
RS RS’ S{HC} HC
Contract checker is stateful
and
acts at runtime
Encode State => Type System
Runtime =>
Compile Time
Session types
session types do the same
for communication
as types do for data
http://groups.inf.ed.ac.uk/abcd/
Session types
codify structure
(communication, data)
and make it available to
programming tools
Scala Example
States
		sealed	trait	State	
		case	class	Packaged				(byWhom:							String)	extends	State	
		case	class	Sending						(whoAccepts:			String)	extends	State	
		case	class	Received				(whoDelivers:		String)	extends	State	
		case	class	Delivered			(toWhom:							String)	extends	State	
		case	class	Lost								(witness:						String)	extends	State	
		case	class	Moving						(tracking:					Long			)	extends	State	
		case	class	Destroyed			(when:			 	 	 				Long			)	extends	State
State Transitions
		sealed	abstract	class	~>[-A,+B]	
		implicit	case	object	GoToThePost			 	 	 	extends	~>[Packaged,Sending]	
		implicit	case	object	AcceptFromSender		 extends	~>[Sending,Moving]	
		implicit	case	object	BringToTheAddress		extends	~>[Moving,Received]	
		implicit	case	object	GiveToReceiver			 	extends	~>[Received,Delivered]	
		implicit	case	object	GetAngry			 	 	 	 	 	extends	~>[Moving,Destroyed]	
		implicit	case	object	DrinkAlcohol			 	 	extends	~>[Moving,Lost]	
		implicit	case	object	StopDrinking			 	 	extends	~>[Lost,Moving]
Resource
	case	class	Parcel[+S<:State](content:	Content,	receiver:	Receiver,	address:	Address)
Server part
			
def	server	=	
				In	{	p:	Parcel[Packaged]	=>	
						val	content	=	"Changed	by	server	"	+	p.content	
						val	result	=	Parcel[Sending](content,	p.receiver,	p.address)	
						val	stop	=	Stop("With	server	result:	"	+	result)	
						(stop,	result)	
				}
Client part
			
		def	client	=	{	
				val	parcel	=	Parcel[Packaged]("Content",	"Receiver",	"Address")	
				val	finish	=	Stop("With	client	result:	"	+	parcel)		
				Out(parcel,	finish)	
		}
Communication steps
	 	
		case	class	Stop(msg:	String)	
	 case	class	In	[R[S<:State],A<:State,B<:State,+C](recv:	R[A]	=>	(C,R[B]))	
(implicit	stateTransition:	~>[A,B])	
		case	class	Out[+R[S<:State],A<:State,+C](data:	R[A],	cont:	C)
Running Session
			
runSession(server,	client)
Session Runner
			
		trait	Session[S]	{	
				type	Self	=	S	
				type	Dual	
				type	DualOf[D]	=	Session[Self]	{	type	Dual	=	D	}	
				def	run	(self:	Self,	dual:	Dual):	Unit	
		}	
		
	def	runSession[AS,D:Session[AS]#DualOf](session:	AS,	dual:	D)	=	
				implicitly[Session[AS]#DualOf[D]].run(session,	dual)
Stop Dual
	 	
	implicit	object	StopDual	extends	Session[Stop]	{	
	 	 type	Dual	=	Stop	
	 	 def	run	(self:	Self,	dual:	Dual):	Unit	=	{}	
	 }
In Dual
	 	
		implicit	def	InDual[R[S<:State],RA<:State,RB<:State,C](implicit	cont:	Session[C])		
				=	new	Session[In[R,RA,RB,C]]	{	
					type	Dual	=	Out[R,RA,cont.Dual]	
					def	run(self:	Self,	dual:	Dual)	=	cont.run(self.recv(dual.data)._1,	dual.cont)	
			}
Type of In Dual
	 	
		implicit	def	InDual[R[S<:State],RA<:State,RB<:State,C](implicit	cont:	Session[C])		
				=	new	Session[In[R,RA,RB,C]]	{	
					type	Dual	=	Out[R,RA,cont.Dual]	
					def	run(self:	Self,	dual:	Dual)	=	cont.run(self.recv(dual.data)._1,	dual.cont)	
			}
Out Dual
			
	implicit	def	OutDual[R[S<:State],RA<:State,RB<:State,C](implicit	cont:	Session[C])		
			=	new	Session[Out[R,RA,C]]	{	
				type	Dual	=	In[R,RA,RB,cont.Dual]	
				def	run(self:	Self,	dual:	Dual)	=	cont.run(self.cont,	dual.recv(self.data)._1)	
		}
Source Code
http://bit.ly/1VnWX2R
Run
scala>	:load	SessionTypes.scala	
Loading	SessionTypes.scala...	
defined	module	SessionTypes	
scala>	SessionTypes.doRun	
Client	results:	Parcel(First,Receiver,Address)	and	
Parcel(Second,Receiver,Address)	
Server	result:	Parcel(Changed	by	server	First,Receiver,Address)	
scala>
Close the post
		sealed	abstract	class	~>[-A,+B]	
		//implicit	case	object	GoToThePost			 	 	 	extends	~>[Packaged,Sending]	
		implicit	case	object	AcceptFromSender		 extends	~>[Sending,Moving]	
		implicit	case	object	BringToTheAddress		extends	~>[Moving,Received]	
		implicit	case	object	GiveToReceiver			 	extends	~>[Received,Delivered]	
		implicit	case	object	GetAngry			 	 	 	 	 	extends	~>[Moving,Destroyed]	
		implicit	case	object	DrinkAlcohol			 	 	extends	~>[Moving,Lost]	
		implicit	case	object	StopDrinking			 	 	extends	~>[Lost,Moving]
Run
scala>	:load	SessionTypes.scala	
Loading	SessionTypes.scala...	
<console>:75:	error:	state	transition	from	SessionTypes.Packaged	to	
SessionTypes.Sending	is	not	allowed	
											In	{	p:	Parcel[Packaged]	=>	
														^	
scala>
Avoid the post
			
def	server	=	
				In	{	p:	Parcel[Packaged]	=>	
						val	content	=	"Changed	by	server	"	+	p.content	
						val	result	=	Parcel[Moving](content,	p.receiver,	p.address)	
						val	stop	=	Stop("With	server	result:	"	+	result)	
						(stop,	result)	
				}
Run
scala>	:load	SessionTypes.scala	
Loading	SessionTypes.scala...	
<console>:75:	error:	state	transition	from	SessionTypes.Packaged	to	
SessionTypes.Moving	is	not	allowed	
											In	{	p:	Parcel[Packaged]	=>	
														^	
scala>
Wrong initial state
			
def	server	=	
				In	{	p:	Parcel[Sending]	=>	
						val	content	=	"Changed	by	server	"	+	p.content	
						val	result	=	Parcel[Moving](content,	p.receiver,	p.address)	
						val	stop	=	Stop("With	server	result:	"	+	result)	
						(stop,	result)	
				}
Run
scala>	:load	SessionTypes.scala	
Loading	SessionTypes.scala...	
<console>:110:	error:	could	not	find	implicit	value	for	evidence	
parameter	of	type	
SessionTypes.Session[SessionTypes.In[SessionTypes.Parcel,SessionTypes
.Sended,SessionTypes.Moving,SessionTypes.Stop]]{type	Dual	=	
SessionTypes.Out[SessionTypes.Parcel,SessionTypes.Packaged,SessionTyp
es.Stop]}	
									def	run	=	runSession(server,	client)	
																													^	
scala>
Misaligned step
			
def	server	=	
				In	{	p:	Parcel[Sending]	=>	
						val	content	=	"Changed	by	server	"	+	p.content	
						val	result	=	Parcel[Moving](content,	p.receiver,	p.address)	
						val	stop	=	Stop("With	server	result:	"	+	result)	
						(Out(result,	stop),	result)	
				}
Run
scala>	:load	SessionTypes.scala	
Loading	SessionTypes.scala...	
<console>:110:	error:	could	not	find	implicit	value	for	evidence	
parameter	of	type	
SessionTypes.Session[SessionTypes.In[SessionTypes.Parcel,SessionTypes
.Sended,SessionTypes.Moving,SessionTypes.Out[SessionTypes.Parcel,Sess
ionTypes.Moving,SessionTypes.Stop]]]{type	Dual	=	
SessionTypes.Out[SessionTypes.Parcel,SessionTypes.Packaged,SessionTyp
es.Stop]}	
									def	run	=	runSession(server,	client)	
																													^	
scala>
?
Session Types Primitives
Sending
Receiving
Sequence
Choice
Recursion
Oops….
Session Types Primitives
Sending
Receiving
Sequence
Choice
Recursion
Session
Types
REST
Contract first, session types never?
• No API Specification standard is about REST
• REST “allows” for client-side contract checking
• Session Types don’t fit RESTful communications
Questions ?
Thank you!

Contract first, session types later?