api design for ISOMORPHIC age

WHOAMI

@minamorl (github.com/minamorl)

Work as a frontend [React] engineer.

LOVE TypeScript/Python.

HOW API DESIGN TREND CHANGED

Text

  • Old age: Define multiple endpoints per action
    • GET /all_users.json
    • GET /user.json
    • POST /create_user.json
    • POST /delete_user.json (Note: this is *not* DELETE)

HOW API DESIGN TREND CHANGED

Text

  • Old age: Define multiple endpoints per action
  • REST got those into more declarative (and resource-based) way:
    • GET /users # All users
    • GET /users/:id # Single user
    • POST /users # Create a single user
    • DELETE /users/:id # Delete a single user

HOW API DESIGN TREND CHANGED

Text

  • Old age: Define multiple endpoints per action
  • REST got those into more declarative (and resource-based) way
  • Single-endpoint based framework (GraphQL/Relay)
    • Large application needs less requests to scale. e.g. Facebook

 

GRAPHQL:

WHAT DID IT

CHANGE?

NO RESOURCE

ONE ENDPOINT

THERE IS A REACT WRAPPER FOR GRAPHQL NAMED RELAY.

DESIGNED FOR DOING ALL OPERATIONS IN ONE SINGLE ENDPOINT

GRAPHQL ITSELF DOESN'T DEPEND ON ANY SPECIFIC LANGUAGE.

CONCEPT

https://medium.com/chute-engineering/graphql-in-the-age-of-rest-apis-b10f2bf09bba#.m3xh3gubu

LEARNING GRAPHQL

JUST {SUCKS}


query Hero($episode: Episode, $withFriends: Boolean!) {
  hero(episode: $episode) {
    name
    friends @include(if: $withFriends) {
      name
    }
  }
}

THIS IS ACTUALLY A [LANGUAGE] WITH UGLY SYNTAX AND TOO MUCH FEATURES.
IT HAS A HUGE LEARNING CURVE.

SO WHAT

I MADE F*CKIN

NEW FRAMEWORK

universal

SINGLE-ENDPOINT

WEBSOCKET- compatible

universal

SINGLE-ENDPOINT

WEBSOCKET- compatible

UNIVERSAL

  • Using same codebase in both.
  • Each endpoint calls looks like normal function calls.
  • Strong TypeScript support.

APPLICATION

import { op, load } from "xhip"
const request = load("request")

export class App {
  @op showAppName() {
    return {
      appName: "xhip example"
    }
  }
  @op showAppVersion() {
    return {
      appVersion: 1
    }
  }
  @op getServerIP() {
    return new Promise((resolve, reject) =>
      request.get('https://api.ipify.org?format=json', (error, response, body) => {
        if (error) reject(error)
        resolve({ ip: JSON.parse(body).ip })
      })
    ).catch(err => {
      console.log(err)
    })
  }
  @op echo(say) {
    return { say }
  }
}
export const app = new App()

Xhip provides its own loader function for isomorphism between server and frontend

Server-side

import { Server } from "xhip-server"
import { app } from "./app.js"

new xhip.Server(app, {
  cors: {
    origin: 'http://localhost:21000', // for CORS support
    credentials: true,
  }
}).listen(8080)

FRONTEND

import { Client } from "xhip-client"

const client = new xhip.Client("http://localhost:8080/", { ssl: false })
client.exec([
  app.showAppName(),
  app.showAppVersion(),
  app.echo("hi"),
  app.getServerIP()
])).then(...)

{
  appName: "xhip example",
  appVersion: 1,
  say: "hi",
  ip: ***.***.***.***
}

STRONG TYPINGS

 

 

 

 

 

for frontend :)

universal

SINGLE-ENDPOINT

WEBSOCKET- compatible

SINGLE-ENDPOINT

  • Have no separated endpoint like RESTful API.
  • All operations will be merged to single JSON/msgpack.
  • Accomplishes same thing with fewer requests.

universal

SINGLE-ENDPOINT

WEBSOCKET- compatible

Websocket-Compatible

  • Any operations can be treated as API and as WebSocket.
  • I am not kidding.

SUBSCRIption model

LET'S TYPE:

http://xhip-example.heroku.com/

ARE YOU READY TO embrace     THE FUTURE?

hope you like Xhip :p

Thanks for listening