REST API in Practice: What, why and how

Your Code

Your Code

Class Foo

Class Bar

Your Code

Class Foo

Foo.X()

Class Bar

Bar.A()

Your Code

Class Foo

Foo.X()

Foo._Y()

Class Bar

Bar.A()

Bar._B()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

Private methods used by Foo.X()

Private methods used by Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

You want to provide this service to your client

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

How?

You want to provide this service to your client

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

Just give the source code to your client

var Foo = require('./YourCode/Foo.js');

var Bar = require('./YourCode/Bar.js');

let f = new Foo();

let b = new Bar();

f.X();

b.A();

// So much win

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

What's the problem with this solution?

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

Your client doesn't know how to write code

var Foo = require('./YourCode/Foo.js');

var Bar = require('./YourCode/Bar.js');

let f = new Foo();

let b = new Bar();

f.X();

b.A();

// So much win

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

Oh! There's another problem!

var Foo = require('./YourCode/Foo.js');

var Bar = require('./YourCode/Bar.js');

let f = new Foo();

let b = new Bar();

f.X();

b.A();

// So much win

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

You don't want to expose your code

var Foo = require('./YourCode/Foo.js');

var Bar = require('./YourCode/Bar.js');

let f = new Foo();

let b = new Bar();

f.X();

b.A();

// So much win

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

What's your solution now?

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

What's your solution now?

"Expose a simple API" - you say

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

But how to expose this service without exposing your code?

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

HTTP Requests

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

HTTP Requests

Server

Request

Response

What's a server anyway?

What's a server anyway?

A simple loop always listening for requests

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

HTTP Requests

Server

Req

Res

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

HTTP Requests

Server

Req

Res

What's missing?

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

HTTP Requests

Server

Req

Res

The main glue

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

HTTP Requests

Server

Req

Res

Endpoints

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

HTTP Requests

Server

Req

Res

Endpoints

/bar

/foo

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

HTTP Requests

Server

Req

Res

Endpoints

/bar

/foo

that.get("/bar", Bar.A())

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

HTTP Requests

Server

Req

Res

Endpoints

/bar

/foo

that.get("/bar", Bar.A())

that.get("/foo", Foo.X())

API

Foo.X()

Bar.A()

Your Code

Class Foo

Class Bar

Foo.X()

Foo._Y()

Foo._Z()

Bar.A()

Bar._B()

Bar._C()

JSON

JSON

HTTP Requests

Server

Req

Res

Endpoints

/bar

/foo

The flow of a request

Incoming request (JSON wrapped in HTTP)

The flow of a request

Incoming request (JSON wrapped in HTTP)

Server forwards to a endpoint

/foo

/bar

The flow of a request

Incoming request (JSON wrapped in HTTP)

Server forwards to a endpoint

/foo

/bar

The flow of a request

Incoming request (JSON wrapped in HTTP)

Server forwards to a endpoint

/foo

/bar

Server calls the method (Server.Foo.X())

The flow of a request

Incoming request (JSON wrapped in HTTP)

Server forwards to a endpoint

/foo

/bar

Server calls the method (Server.Foo.X())

Foo.X() processes the request and return response

Core logic

e.g: addDataset()

Core logic

e.g: addDataset()

Server method to handle Req/Res

e.g: Server.Dataset()

Core logic

e.g: addDataset()

Server method to handle Req/Res

Endpoint that will call a server method to handle the request

e.g: that.server.put("/dataset/:id", Server.dataset())

e.g: Server.Dataset()

How the addDataset would look like as a REST API service

How the addDataset would look like as a REST API service

that.rest.put('dataset/:id', SomeClass.putDataset);

How the addDataset would look like as a REST API service

putDataset (req: restify.Request, res: restify.Response, next: restify.Next) {
        // Get the dataset data coming from the request
        let dataStr = new Buffer(req.params.body).toString('base64');
        
        let iFacade = new InsightFacade();
        let datasetName = req.params.id;
        
        // Call your good old AddDataset() -- Remember it is an ASYNC function!!
        // ...
        // ...
        // ...

        // Write to response object the code you're returning
        res.status(value.code);

        // Write to response object the json data you're returning
        res.json(value);

        // Return this. Because.
        return next();
}

How the addDataset would look like as a REST API service

it("It should be able to put the dataset", function () {
        // Point to your local test dataset
        let file = __dirname + "/rooms.zip";
        
        // Make the request to your local machine (you are running the server locally)
        return chai.request('http://localhost:4321')
            .put('/dataset/rooms')
            .attach("body", fs.readFileSync(file), file)
            .then(function (res: restify.Response) {
                //Log.trace('then:' + JSON.stringify(res));
                expect(res.status).to.equal(204);
            })
});

REST API in Practice: What, why and how v2

By Rodrigo Araújo

REST API in Practice: What, why and how v2

  • 1,509