CSS calc, you little beauty

When you have something like a React/material-ui appbar and maybe toolbars these would usually by set to a pixel height which is great, until we want to then expand a component beneath them and have it fill the available space ?

CSS calc() is here to save the day.

Here’s an example style in material-ui style code. In this code our appbar and toolbar’s combined height is 123px and we want the next component to fill the “container”. The following therefore calculates the available space by subtracting 123px from whatever 100% is.

const styles = (_theme: Theme) => ({
  container: {
    width: '100%',
    height: 'calc(100% - 123px)'
  },
});

Obviously we need to wrap our parent component in the withStyles function, i.e.

export withStyles(styles)(MyComponent);

then in the render method

const { classes } = this.props as any;
// ...
<div className={classes.container}>
// component to fill this space
</div>

Decorators (attributes/annotations) in TypeScript

TypeScript experimental (enabled by setting “experimentalDecorators”: true within the tsconfig.json) enables a feature known as decorators, in C# we call them attributes and Java they’re annotations. Basically they are way to extend the functionality of classes, either by adding meta data or adding code to enable AOP type functionality.

To define a decorator we simple write a function which is evaluated, then called by the runtime allow for us to write AOP etc.

A decorator function takes different arguments depending upon whether it’s used on a class, property, parameter or method. Let’s assume we were to create a logging AOP decorator, we’d use the following signatures.

Let’s assume we’re writing one of those classic AOP functions, a log function.

Class Decorators

The class decorator has a simple form, a single argument of type Function. This argument is basically our class function.

function logClass(target: Function): any {
  // implementation
}

If our desire is to intercept and effect the creation of our classes then we will need to execute this Function and then in essence add our own prototypes or the likes. If our aim is to log the creation of this class, for example if we want to view performance numbers, then we can obviously log before and after creation via the decorator.

Let’s create a fairly standard looking class decorator which in this case has extended the logClass signature to be type safe

function logClass<T extends {new(...constructorArgs: any[]): any}>(ctor: T) {
  const newCtor: any = function (...args: any[]) {
    // pre ctor invocation
    const f: any = function () {
      return new ctor(...args);
    }
    f.prototype = ctor.prototype;
    const instance: any = new f();
    // post ctor invocation
    return instance;
  }
  newCtor.prototype = ctor.prototype;
  return newCtor;
}

If we want to get the name of the class we (at least in TypeScript) will need to have a line such as

const target: any = ctor;

and from this target we can now get the name of the type, for example

console.log(target.name);

In usages we simply write the following

@logClass
class MyClass {
}

Method Decorators

The method decorator is somewhat more complicated, as one would expect, as it takes three arguments, looking like this

function logMethod(
  target: any, propertyKey: string, 
  propertyDescriptor: PropertyDescriptor): PropertyDescriptor {
  // implementation
}

The first argument is the instance of the class, the second is the method name and the final one relates to the PropertyDescriptor parameters for the method which is of the following sample shape

{
  value: [Function],
  writable: true,
  enumerable: true,
  configurable: true
}

For a usage example we might write something like this

function logMethod(target: any, 
   propertyKey: string, 
   propertyDescriptor: PropertyDescriptor): PropertyDescriptor {
  const method = propertyDescriptor.value;
  propertyDescriptor.value = function (...args: any[]) {
    // pre method call
    const result = method.apply(this, args);
    // post method call
    return result;
  }
  return propertyDescriptor;
};

In usages we simply write the following

class MyClass {
   @logMethod
   run(): void {
   }
}

Parameter Decorators

We can apply a decorator to an argument/parameter of a method with a decorator with the parameters show below

function logParameter(
   target: any, propertyKey: string | symbol, 
   propertyIndex: number): void {
  // implementation
}

The target is the instance of the target object, the propertyKey is the name of the method the parameter we’re decorating is on.

Note: As per TypeScript documentation on this decorator – a parameter decorator can only be used to observe that a parameter has been declared on a method.

In usages we simply write the following

class MyClass {
   @logMethod
   run(@logParameter options: any): void {
   }
}

You’ll notice the addition of the logMethod in the example above. The thing is the parameter decorator in this case needs to work alongside the method decorator because the parameters within this decorator will simply be the instance of the object or prototype, the method name and the index of the parameter. There isn’t any way from these three parameters to directly get the value passed into the parameter, hence we’d probably tend towards using the logParameter to add a prototype or the likes to allow the logMethod to then query for these prototypes.

However we might also be able to utilities the reflect-metadata npm package to embed meta data alongside our types – we’ll look at this in another post.

Property Decorators

A property in TypeScript is a field in C# terms. The format of the function is shown below, as per other functions, the target is the object or prototype. The propertyKey is the name of the property/field the decorator’s associated with.

function logProperty(target: any, propertyKey: string): void {
  // implementation
}

In usages we simply write the following

class MyClass {
   @logProperty
   public running: boolean;
}

We can insert our own implementation of the property’s getter/setter in the following way

function logProperty(target: any, propertyKey: string): void {

  let value = target[propertyKey];
  const getter = () => {
    return value + " Doo";
  };

  const setter = (newVal: any) => {
    value = newVal;
  };

  if (delete target[propertyKey]) {
    Object.defineProperty(target, propertyKey, {
      get: getter,
      set: setter,
      enumerable: true,
      configurable: true
    });
  }
}

In the above we create our own getter and setter, then remove the existing property replacing with our own.

Further…

Decorators are (at the time of writing this) in stage 2 proposal state, see https://github.com/tc39/proposal-decorators and are different in implementation to those experimental features within TypeScript.

Apollo GraphQL client

Based upon our previous implementation(s) of a server it’s now time to write some client code.

  • yarn add apollo-client
  • yarn add apollo-cache-inmemory
  • yarn add apollo-link-http
  • yarn add graphql-tag
  • yarn add isomorphic-fetch
  • yarn add -D @types/isomorphic-fetch

Now let’s create a simple script entry (this extends the previous post’s scripts section)

"scripts": {
  "build": "tsc",
  "client": "node client.js"
}

Now let’s create the file client.ts which should look like this

import ApolloClient from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
import gql from 'graphql-tag';
import fetch from 'isomorphic-fetch';

const cache = new InMemoryCache();
const link = new HttpLink({
  uri: 'http://localhost:4000/',
  fetch: fetch
})

const client = new ApolloClient({
  cache,
  link,
});

client.query({
  query: gql`
    {
    users {
      firstName
      lastName
    }
  }`
  })
  .then((response: any) => console.log(response.data.users));

The response.data.users should now output the array of User objects.

Here’s an example of a mutation

client.mutate({
  mutation: gql`
    mutation {
      create(user: {
        firstName: "Miner",
        lastName: "FortyNiner"
      }) {
        firstName
        lastName
      }
    }
  `
}).then((response: any) => console.log(response.data.create));

Note: I had lots of issues around the fetch code, with errors such as Invariant Violation:
fetch is not found globally and no fetcher passed, to fix pass a fetch for your environment like
https://www.npmjs.com/package/node-fetch.
. The addition of the isomorphic-fetch solved this problem.

Writing our first Apollo GraphQL server

In the previous posts we’ve seen how to build an express based server and eventually add GraphQL to it.

graphql-express is not the only option for implementing GraphQL servers, let’s now look at Apollo – I cannot say whether one library is better than the other as I’ve not used them enough to comment although.

Let’s go through the process of creating a new project for this, so carry out the following steps

  • Create a folder for your project
  • cd to that folder
  • Run yarn init -y
  • Run tsc –init
  • Add a folder named models and a file named user.ts (we’ll use the same model/data from the previous posts), here’s the code for this file
    export default class User {
      constructor(public firstName: string, public lastName: string) {
      }
    }
    
    export const stubData = [
      new User('Scooby', 'Doo'),
      new User('Fred', 'Jones'),
      new User('Velma', 'Dinkley'),
      new User('Daphne', 'Blake'),
      new User('Shaggy', 'Rogers'),
    ];
    

So that’s the basics in place for the support data and model, let’s now look at the specifics for Apollo.

We’re going to create a file for the resolvers named resolver.ts and here’s the code

import User, { stubData } from "./models/user";

export const resolvers = {
  Query: {
    users: () => stubData,
  },
  Mutation: {
    create: (parent: any, args: any): User => {
      const data = new User(args.user.firstName, args.user.lastName)
      stubData.push(data);
      return data;
    }
  }
}

As you can see, we specify the Query and Mutation separately and the code’s pretty much the same as the express-graphql implementation except in the create mutation parameters. In this case the parent will supply any parent nodes whilst the args supplies the parameters from the mutation call.

Now we’ll create the file server.ts which will have the (as I’m sure you guessed) the server code as well as the schema definition (Apollo names this typeDefs).

import { ApolloServer, gql } from "apollo-server";
import { resolvers } from "./resolvers";

const typeDefs = gql`
type User {
    firstName: String
    lastName: String
  }

  input UserInput {
    firstName: String
    lastName: String
  }

  type Mutation {
    create(user: UserInput): User
  }

  type Query {
    users: [User]
  }
`;

const server = new ApolloServer({ typeDefs, resolvers });

server.listen()
  .then(({ url }) => {
    console.log(`Server listening to ${url}`);
  });

Note that Apollo uses a template tag gql function to declare the GraphQL schema, which along with the resolves is passed into the ApolloServer, then we simply start the server.

If you now run yarn build followed by yarn run the server will run up with default port 4000. Navigating to http://localhost:4000/ will display the GraphQL playground.

So, as you can see, Apollo is very simple to set-up for use as a GraphQL server.

Adding GraphQL to our Express server

In the previous two posts, we firstly create a basic server, then extended this with REST functionality, now lets add GraphQL capabilities.

First off, run the following

  • yarn add express-graphql graphql
  • Add a folder named schema

With the schema folder add a new file userSchema.ts with the following code

import { buildSchema } from "graphql";

export const schema = buildSchema(`
  type User {
    firstName: String
    lastName: String
  }

  type Query {
    users: [User]
  }
`);

In the above code, we create a GraphQL schema based upon our User type, along with the type Query for us to use the User type.

Next we’ll create a folder named resolvers along with the file userResolver.ts. GraphQL uses resolvers to interact with the data via GraphQL (like the code in the indexController in the previous post).

import { stubData } from "../models/user";

export const userResolver = {
  users: () => {
    return stubData;
  }
}

Now let’s update the server.ts file by adding the GraphQL code, I’ll include the whole file here (at least the specifics for GraphQL)

import graphqlHTTP from "express-graphql";
import { schema } from "./schema/userSchema";
import { userResolver } from "./resolvers/userResolver";

const server = express();

server.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: userResolver,
  graphiql: true,
}));

const port = 4000;
server.listen(port,
  () => console.log(`Server on port ${port}`)
);

In the above we’ve specified graphiql: true which allows us to via the GraphIQL page using http://localhost:4000/graphql

Now if you type the following into the left hand (query) pane

{
  users {
    firstName
    lastName
  }
}

Running this from GraphIQL should output all our stubData.

We’ve essentially got the users method from our original code but now let’s add the equivalent of the create method, which in GraphQL terms is a mutation type.

In the userSchema.ts file, change the schema to look like this

export const schema = buildSchema(`
  type User {
    firstName: String
    lastName: String
  }

  input UserInput {
    firstName: String
    lastName: String
  }

  type Mutation {
    create(user: UserInput): User
  }

  type Query {
    users: [User]
  }
`);

We’ve added an input type UserInput along with the type Mutation. Next, within the userResolve.ts file change the userResolve to add the create function, as below

export const userResolver = {
  users: () => {
    return stubData;
  },
  create: (data: any) => {
    stubData.push(new User(data.user.firstName, data.user.lastName)); 
    return data.user;
  }
}

Let’s test this code by executing the following query via GraphIQL

mutation {
  create(user: {
    firstName: "Miner",
    lastName: "FortyNiner",
  }) {
    firstName
    lastName
  }
}

Extending our Express based server

In my previous post I showed how to create an Express server in TypeScript. Let’s now extend things…

To start with, create some folders (the names are not important, in that this is not using convention based folder names). We’re going to set things up in a similar way to I’ve done for C# and Java…

  • Add a new folder controllers
  • Add a new folder models

Create a file server.ts in the root folder. Here’s the code from the previous post plus some extras

import express from "express";
import bodyParser from "body-parser";

const server = express();

server.use(bodyParser.json());

server.get("/", (request, response) => {
  response.send("<h1>Hello World</h1>");
});

const port = 4000;
server.listen(port, 
  () => console.log(`Server on port ${port}`)
);

The body-parser exposes middleware etc. in this case we’re adding the ability to work with JSON content type.

Now let’s change the existing route / and add some more, below is the additional code required in server.ts

import * as indexController from "./controllers/indexController";

server.get('/', indexController.index);
server.get('/users', indexController.users);
server.get('/users/create', indexController.create);

// POST implementation
// server.post('/users/create', indexController.create);

We now need to implement the model and the controller, so starting with the model, create the file user.ts within the models folder and it should look like this

export default class User {
  constructor(public firstName: string, public lastName: string) {
  }
}

export const stubData = [
  new User('Scooby', 'Doo'),
  new User('Fred', 'Jones'),
  new User('Velma', 'Dinkley'),
  new User('Daphne', 'Blake'),
  new User('Shaggy', 'Rogers'),
];

The stubData ofcourse is just here to give us some data to start things off.

In the controllers folder, add a new file named indexController.ts and the file should look like this

import { Request, Response } from "express";
import User, { stubData } from '../models/user';

export const index = (req: Request, res: Response) => {
  res.send("<h1>Methods are</h1><ul><li>users</li><li>create</li></ul>")
};

export const users = (req: Request, res: Response) => {
  res.json(stubData);
};

export const create = (req: Request, res: Response) => {
  const newUser = new User(req.query.firstName, req.query.lastName);
  stubData.push(newUser);
  res.json(newUser);
};

// POST implementation
// export const create = (req: Request, res: Response) => {
//   const newUser = new User(req.body.firstName, req.body.lastName);
//   stubData.push(newUser);
//   res.json(newUser);
// };

The scripts for package.json should also be taken from the previous post.

If you now run yarn build then yarn start your server will be up and running. Using the following URL’s

  • http://localhost:4000/
  • http://localhost:4000/users
  • http://localhost:4000/users/create?firstName=Miner&lastName=FortyNiner
  • will result in, the first URL returning a simple help screen using HTML, the second will list the current array of users using JSON and finally the third URL will create a new user, the response will show the new user as JSON, but if you call the users method again you will see the newly added user.

    I’ve also listed the POST implementations which you’d probably more likely use for mutations, but the GET implementations are fine in this instance and easier to test via our preferred browser.

Express server with TypeScript

Express is a popular web application server in JavaScript.

Let’s create a really quick and simple expression server which will be a good starting point for further posts which use this library.

I’ll assume you’ve created a folder, run yarn init and tsc –init, next up run

  • yarn add express
  • yarn add -D @types/express
  • Add a new file, mine’s named server.ts
  • Add the usual scripts
    "scripts": {
      "build": "tsc",
      "start": "node server.js"
    }
    

The code to run up a really simple server is as follows

import express from "express";

const server = express();

server.get("/", (request, response) => {
  response.send("<h1>Hello World</h1>");
});

const port = 4000;
server.listen(port, 
  () => console.log(`Server on port ${port}`)
);

Using our scripts, run yarn build followed by yarn start. The server should start on port 4000, so now navigate to http://localhost:4000 using your preferred browser and that’s it.

We’ve created a server instance on port 4000, we’re routed any root (i.e. /) calls to the response, which in this case returns a simple HTML string.

The “is” type guard in TypeScript

The is keyword can be used to narrow types in TypeScript. What this means is that, for example if we’re testing whether an any parameter is a string a number or whatever, TypeScript will see the type as that type in subsequent code.

For example if we have the following functions

function isString(test: any): test is string {
  return typeof test === "string";
}

function isNumber(test: any): test is number {
  return typeof test === "number";
}

Each function simply takes a parameter of type any then if the return is true the parameter in subsequent code is seen by TypeScript as that type, i.e. Let’s assuming we have a some function which happens to use these functions, like this

function run(a: any) {
  if(isString(a)) {
    console.log(a)
  }
  if(isNumber(a)) {
    console.log(a)
  }
}

If you’re using Visual Code (for example) the TypeScript type popup (display when you move the mouse over the parameter a will show the type to be any in the run parameter list, or in any of the isXXX function parameters. But in the console.log after each isXXX function, TypeScript will interpret the type to be a string (in the case of isString) and a number (in the case if isNumber) hence using intellisense on the variables will list the methods etc. for a string and those for a number respectively

So basically the is keyword will appear to convert the parameter to the specified type if the function returns true.

To look at it another way we could instead write something like this

function isString(test: any): boolean {
    return typeof test === "string";
}

function isNumber(test: any): boolean {
    return typeof test === "number";
}

function run(a: any) {
  if(isString(a)) {
    const b = a as string;
    console.log(b)
  }
  if(isNumber(a)) {
    const b = a as string;
    console.log(b)
  }
}

For completeness, here’s the function syntax for a const style function

const isString = (test: any): test is string => {
  return typeof test === "string";
}

Simple node based HTTP server

In a previous post we used webpack to run an HTTP server, in this post we’re going to create a bare bones HTTP server using the http package.

In your chosen folder run the usual commands

  • yarn init y
  • tsc –init
  • Add a folder named public off of the folder you source will be in (this will be where we add static html files)

Now lets’ add the required packages

  • yarn add node-static @types/node-static

Add the following to the package.json

"scripts": {
  "start": "node server.js",
  "build": "tsc"
}

In the public folder add index.html with the following

<html>
  <head></head>
  <body>
  Hello World
  </body>
</html>

Now let’s add the code to start up our server (mine’s in the file server.ts)

import ns from "node-static";
import http from "http"

const file = new ns.Server("./public");

http.createServer((request, response) => {
    request.addListener("end", () => {
        file.serve(request, response);
    })
    .resume()
})
.listen(4000);

Simple run yarn build then yarn start and the server will start. Navigating your preferred browser to http://localhost:4000/ will then display the HTML file, i.e. Hello World text.

Websockets with JavaScript

Let’s create a JavaScript websocket server.

To start with carry out the following steps…

  • Create a folder, mine’s wsserver and cd to it
  • Run yarn init -y
  • Run tsc –init
  • Run yarn add ws @types/ws
  • Add a file (mine’s server.ts) for our server code
  • Add another file this time for a sample client (mine’s client.ts)
    • Now we will add the scripts, so add the following to package.json

      "scripts": {
        "server": "node server.js",
        "client": "node client.js"
        "build": "tsc"
      }
      

      Let’s add some code, in the server.js put the following

      import WebSocket from "ws";
      
      const wss = new WebSocket.Server({ port: 4000 });
      
      wss.on("connection", ws => {
        ws.on('message', message => {
          console.log('received: %s', message);
        });
      
        ws.on("close", () => {
          console.log("Close connection");
        });
      
        ws.send("Server says Hi");
      });
      

      In the above code we create a new websocket server on port 4000 then we handle any connection’s (once a connection is made the server sends back the message “Server says Hi”. The ws.on “message” will output any messages sent from the client. It should be fairly obvious that the “close” is called when a connection is closed.

      Let’s now put the following in the client.ts

      import WebSocket from "ws";
      
      const ws = new WebSocket("ws://localhost:4000");
      
      ws.onopen = () => {
        ws.send("Client says Hi");
      };
      
      ws.onerror = error => {
        console.log(error);
      }
      
      ws.onmessage = msg => {    
        console.log(`Client onmessage: ${msg.data}`);
      }
      
      ws.onclose = () => {
        console.log("Close");
      };
      

      In the above we open the connection to the web socket server, when the connection is open (onopen) we send a message “Client says Hi” to the server, obviously any errors are sent to the onerror function and any message from the server are routed to the onmessage function, finally onclose is called if the server closes the connection.

      Now run the script command yarn build and then in one terminal run yarn server and in another terminal run yarn client.

      We can also send specific commands to the server, for example in the client add the following to the onopen function

      ws.send("getData");
      

      Within the server add the following

      ws.on("getData", msg => {
        console.log("getData called")
      });
      

      So now when the server receives a getData messages it’s routed to this server function.

      If we have multiple client’s connecting to a server, we can send messages to each client using code, like the following

      wss.clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
          client.send("Broadcasting a  message);
        }
      });
      

      We can also extend the server “connection” function like this

      wss.on("connection", (ws, request) => {
        console.log(request);
      }
      

      The request parameter allows us to check the request.url if we want to change take different actions depending upon the query part of the websocket URL.

      It’s often useful to implement ping/pong capabilities which would allow us to check if the client still exists, here’s rather simplistic example of this type of code.

      wss.on("connection", (ws, request) => {
        ws.isAlive = true;
      
        ws.on("pong", () => {
          console.log("Pong called");
          ws.isAlive = true;
        });
      
        setInterval(function ping() {
          wss.clients.forEach(function each(ws: any) {
            if (ws.isAlive === false)  {
              console.log("Terminated client")
              return ws.terminate();
            }
              
            ws.isAlive = false;
            console.log("Ping client")
            ws.ping();
          });
        }, 10000);
      });