Skip to content

Server API Overwiew

Peri edited this page Feb 20, 2022 · 3 revisions

The plaything.io server supports both Web Sockets and regular Http[s] requests. Web Sockets are required to take full advantage of Subscribe calls as they allow for real-time updates rather than a one time fetch.

Every API call can be found in Api.ts

Security

Currently, plaything.io only works with http:// (not https://) and ws:// (not wss://). This is not secure. It will be addressed in the future.

Web Sockets

To connect a Web Socket, simply upgrade the connection to the http[s] server by connecting to ws[s]://address. Web Sockets send data over as a JSON object. Most or all messages sent from the client will include a { type: string } header which indicates the message type.

To identify a response to a given message - if one is expected - a Web Socket can include an { id: number } header, which will be mirrored in the response.

Web Sockets do not need to send session keys over (when a message requires it) because the server automatically maps a Web Socket to a session. Nevertheless, when a Web Socket disconnects, that mapping is removed but can simply be restored with the RequestSessionReconnect which accepts a { sessionKey: string } field. This field is included in all session messages, but is optional for Web Sockets as long as the internal mapping exists.

Http[s] Requests

Http[s] requests have their own request-response identification system and as such do not need the id header, however it can still be used.

Http[s] requests are realized at the /api/<type> or /api/<SESSION_KEY>/<type> endpoint.

All request fields are serialized JSON embedded into the GET query as properties of an object. For example /api/login?nickname=myNickname will send the following object: { type: 'login', nickname: 'myNickname' }

The response to a Http[s] request will have a json/application MIME type.


An invalid call, such as a Web Socket call that is not a JSON object or a Http[s] call to an invalid location will result in an { error: 'incorrect API call' } response.

Client call categories

Request

An Api.Request* call:

  • Has a type: string field. If this field is an invalid value, the server will respond with { error: 'Invalid request' }
  • Might require a { sessionKey: string } header (API.SessionRequest). If no session key is provided and no internal mapping (for a Web Socket) exists, the server will respond with { result: 'session not found' } (API.InvalidSession)
  • If the call is successful, the server will respond with a corresponding API.Response*. There exists a mapping from the request type field to response type - RequestResponseMap - it can be used to strongly type API call handlers

Subscribe

An API.Subscribe* call:

  • Has a type: string field
  • Might require an API.SessionRequest header
  • If the call is successful, the server will respond with a corresponding API.Response*. It is part of the RequestResponseMap. This response will have all current information
  • If the call is made over a Web Socket, it will subscribe it to Heartbeat events which inform about real-time changes to the resource. This kind of subscription is cancelled automatically when the Web Socket closes or you no longer have access to the resource, for example - after leaving a room

Message

An API.Message* call:

  • Has a type: string field
  • Might require an API.SessionRequest header
  • Is a fire-and-forget call and will not generate a server response

Server call categories

Response

An API.Response*:

  • Has to mirror the { id: number } request header if present
  • Might have a { result: string } header indicating if the request succeeded ('ok') or not (anything else, as an informative message from a closed set of options)

Heartbeat

An API.Heartbeat*:

  • Is a real-time update the server sends to Web Sockets
  • Has a type: string field which starts with 'heartbeat-'
  • Might have a kind: string field which indicates what kind of update it is. For example 'added', 'updated' or 'removed'

Server API typing convention

All API types need to be located inside the API namespace in Api.ts

All API categories need static type checking. For example, the Request category is organized like this:

export type RequestA = { ... }
export type RequestB = { ... }
export type RequestC = { ... }

type RequestTypes = RequestA | RequestB | RequestC            // this type is not exported as it is not checked yet
export type Request = Extract<RequestTypes, { type: string }> // make sure all request types have a type field

All API requests that have a response need to be a part of the RequestResponseMap

When an API call needs an active session, the request type must be an & union with the API.SessionRequest type and the response must be an | union with the API.InvalidSession type.