REST is Bad
Kfir Bloch
Head of Backend Engineering @Wix.com
github.com/kfiron@kfirondevkfirb@wix.com
Restful API between Microservices
is the worst choice you can make.
POST http://sms-server/messages
{
"from": "054-555-6666",
"to": "055-222-333",
"message": "hi, what's up Rony"
}
Response
Status code 200
{
“id”: “55666322123”,
“success”: true
}
SMS Server
GET http://sms-server/messages/0545556666
[
{
”id:" “55666322123”,
"to:" "055-222-3333",
"message": "hi, what's up Rony"
},
{
”id:" “44666322345”,
"to:" "055-111-4444",
"message": "I am sleeping"
}
]
But that’s not enough, is it?
POST http://sms-server/messages
Accept: “json” / “xml”
{
"from": "054-555-6666",
"to:" "055-222-333",
"message": "hi, what's up Rony"
}
You’ll want to ask for a payload type
Smelly!
Mix between
API protocol and
semantics
POST http://sms-server/messages
Accept: “json” / “xml”
Authorization: AWSAKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCw/
Timestamp: 2677432356
{
"from": "054-555-6666",
"to:" "055-222-333",
"message": "hi, what's up Rony"
}
You’ll need security
Hash calculate
is a difficult, complex
integration
POST http://sms-server/messages
Accept: “json” / “xml”
Authorization: AWSAKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCw/
Timestamp: 2677432356
X-Tenant-ID: bc145c6c-c543-43e6-8d7d-f7012f7412cf
{
"from": "054-555-6666",
"to:" "055-222-333",
"message": "hi, what's up Rony"
}
and sometimes tenant identification
POST http://sms-server/messages
Accept: “json” / “xml”
Authorization: AWSAKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCw/
Timestamp: 2677432356
X-Tenant-ID: bc145c6c-c543-43e6-8d7d-f7012f7412cf
Accept-Language: en
{
"from": "054-555-6666",
"to:" "055-222-333",
"message": "hi, what's up Rony"
}
and language
POST http://sms-server/messages?page=1
Accept: “json” / “xml”
Authorization: AWSAKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCw/
Timestamp: 2677432356
X-Tenant-ID: bc145c6c-c543-43e6-8d7d-f7012f7412cf
Accept-Language: en
{
"from": "054-555-6666",
"to:" "055-222-333",
"message": "hi, what's up Rony"
}
Sometimes you have parameters
POST http://sms-server/messages?page=1
Accept: “json” / “xml”
Authorization: AWSAKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCw/
Timestamp: 2677432356
X-Tenant-ID: bc145c6c-c543-43e6-8d7d-f7012f7412cf
Accept-Language: en
Cache-Control: max-age=0
{
"from": "054-555-6666",
"to:" "055-222-333",
"message": "hi, what's up Rony"
}
and cache control
and rate-limiting support
Status: 403 Forbidden
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1377013266
Connection: keep-alive
POST http://sms-server/messages?page=1
Accept-Language: en
Authorization: xxkgkkgslslls;ffgg/
Timestamp: 324884545454
X-Tenant-ID: bc145c6c-c543-43e6-8d7d-f7012f7412cf
{
"from": "054-555-6666", "to:" "055-222-333", "message": "hi, what's up
Rony"
}
Status: 403 Forbidden
Cache-Control: max-age=0
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
and you end up with something like this
Verbose!
It’s difficult to
document
a broken API
Adding more requests,
another protocol integration?
Continuous Integration is painful.
We want to break CI whenever the protocol changes.
Should we run all servers
to test this thing?
How your code will look like
String url = "http://sms-server/messages?page=1";
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
// add request header
request.addHeader(”Authorization", calculateHash(request));
request.addHeader(”Accept", “json”);
HttpResponse response = client.execute(request);
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
Verbose!
So we hide the pain into a function
public class SMSService {
public SMSResponse sendSMS(Message message);
public SMSMessages messagesForUser(UUID user);
}
RPC is a
proper solution Hide network complexity and
focus on the API semantic
Calling a function and
implementing a function is simple
We do RPC
since the 70’s
CORBA RMI Spring-Remoting
JSON-RPC XML-RPC SOAP
Thrift Protobuf Avro
Akka-Remoting Lagom Grpc
Why RPC is
good for you
It’s easy to use
It covers cross cutting concerns
Dependency with IDL as source of
truth – breaks in CI
It has proper error handling
Proper documentation
Thank You
github.com/kfiron@kfirondevkfirb@wix.com

Rest is bad

  • 1.
    REST is Bad KfirBloch Head of Backend Engineering @Wix.com github.com/kfiron@kfirondevkfirb@wix.com
  • 2.
    Restful API betweenMicroservices is the worst choice you can make.
  • 3.
    POST http://sms-server/messages { "from": "054-555-6666", "to":"055-222-333", "message": "hi, what's up Rony" } Response Status code 200 { “id”: “55666322123”, “success”: true } SMS Server
  • 4.
    GET http://sms-server/messages/0545556666 [ { ”id:" “55666322123”, "to:""055-222-3333", "message": "hi, what's up Rony" }, { ”id:" “44666322345”, "to:" "055-111-4444", "message": "I am sleeping" } ]
  • 5.
    But that’s notenough, is it?
  • 6.
    POST http://sms-server/messages Accept: “json”/ “xml” { "from": "054-555-6666", "to:" "055-222-333", "message": "hi, what's up Rony" } You’ll want to ask for a payload type Smelly! Mix between API protocol and semantics
  • 7.
    POST http://sms-server/messages Accept: “json”/ “xml” Authorization: AWSAKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCw/ Timestamp: 2677432356 { "from": "054-555-6666", "to:" "055-222-333", "message": "hi, what's up Rony" } You’ll need security Hash calculate is a difficult, complex integration
  • 8.
    POST http://sms-server/messages Accept: “json”/ “xml” Authorization: AWSAKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCw/ Timestamp: 2677432356 X-Tenant-ID: bc145c6c-c543-43e6-8d7d-f7012f7412cf { "from": "054-555-6666", "to:" "055-222-333", "message": "hi, what's up Rony" } and sometimes tenant identification
  • 9.
    POST http://sms-server/messages Accept: “json”/ “xml” Authorization: AWSAKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCw/ Timestamp: 2677432356 X-Tenant-ID: bc145c6c-c543-43e6-8d7d-f7012f7412cf Accept-Language: en { "from": "054-555-6666", "to:" "055-222-333", "message": "hi, what's up Rony" } and language
  • 10.
    POST http://sms-server/messages?page=1 Accept: “json”/ “xml” Authorization: AWSAKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCw/ Timestamp: 2677432356 X-Tenant-ID: bc145c6c-c543-43e6-8d7d-f7012f7412cf Accept-Language: en { "from": "054-555-6666", "to:" "055-222-333", "message": "hi, what's up Rony" } Sometimes you have parameters
  • 11.
    POST http://sms-server/messages?page=1 Accept: “json”/ “xml” Authorization: AWSAKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCw/ Timestamp: 2677432356 X-Tenant-ID: bc145c6c-c543-43e6-8d7d-f7012f7412cf Accept-Language: en Cache-Control: max-age=0 { "from": "054-555-6666", "to:" "055-222-333", "message": "hi, what's up Rony" } and cache control
  • 12.
    and rate-limiting support Status:403 Forbidden X-RateLimit-Limit: 60 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1377013266 Connection: keep-alive
  • 13.
    POST http://sms-server/messages?page=1 Accept-Language: en Authorization:xxkgkkgslslls;ffgg/ Timestamp: 324884545454 X-Tenant-ID: bc145c6c-c543-43e6-8d7d-f7012f7412cf { "from": "054-555-6666", "to:" "055-222-333", "message": "hi, what's up Rony" } Status: 403 Forbidden Cache-Control: max-age=0 X-RateLimit-Limit: 60 X-RateLimit-Remaining: 0 and you end up with something like this Verbose! It’s difficult to document a broken API
  • 14.
    Adding more requests, anotherprotocol integration?
  • 15.
    Continuous Integration ispainful. We want to break CI whenever the protocol changes.
  • 16.
    Should we runall servers to test this thing?
  • 17.
    How your codewill look like String url = "http://sms-server/messages?page=1"; HttpClient client = new DefaultHttpClient(); HttpGet request = new HttpGet(url); // add request header request.addHeader(”Authorization", calculateHash(request)); request.addHeader(”Accept", “json”); HttpResponse response = client.execute(request); BufferedReader rd = new BufferedReader( new InputStreamReader(response.getEntity().getContent())); StringBuffer result = new StringBuffer(); String line = ""; while ((line = rd.readLine()) != null) { result.append(line); } Verbose!
  • 18.
    So we hidethe pain into a function public class SMSService { public SMSResponse sendSMS(Message message); public SMSMessages messagesForUser(UUID user); }
  • 19.
    RPC is a propersolution Hide network complexity and focus on the API semantic Calling a function and implementing a function is simple
  • 20.
    We do RPC sincethe 70’s CORBA RMI Spring-Remoting JSON-RPC XML-RPC SOAP Thrift Protobuf Avro Akka-Remoting Lagom Grpc
  • 21.
    Why RPC is goodfor you It’s easy to use It covers cross cutting concerns Dependency with IDL as source of truth – breaks in CI It has proper error handling Proper documentation
  • 22.