Categories
GraphQL JavaScript

Creating a GraphQL Server with Express and Apollo Server

Apollo Server is available as a Node package. We can use it to create a server to accept GraphQL requests.

In this article, we’ll look at how to use it with Express to create our own GraphQL server.

Get started with Apollo Server

We get started by installing the express-apollo-server.

To install it with Express, we run:

npm install apollo-server-express express

Then create an index.js file and add:

const express = require('express');  
const { ApolloServer, gql } = require('apollo-server-express');
const books = [  
  {  
    title: 'JavaScript for Dummies',  
    author: 'Jane Smith',  
  },  
  {  
    title: 'JavaScript Book',  
    author: 'Michael Smith',  
  },  
];

const typeDefs = gql`  
  type Book {  
    title: String  
    author: String  
  } type Query {  
    books: [Book]  
  }  
`;

const resolvers = {  
  Query: {  
    books: () => books,  
  },  
};

const app = express();  
const server = new ApolloServer({ typeDefs, resolvers });  
server.applyMiddleware({ app });
app.listen(3000, () => console.log('server started'));

In the code above, we created our basic Apollo GraphQL server by creating our data in the books array.

Then we used the gql tag with our schema definition string passed in to create our schema and assigned it to the typedefs constant.

The query type is always required so we can query data from our server. The server won’t run without it.

We created a Book type with fields title and author . Then we created a books query to return an array of Books.

Next, we created our resolvers so that we can query the data we created. We just created a books resolve to return the books array.

Finally, we have the following initialization code to load the server:

const app = express();  
const server = new ApolloServer({ typeDefs, resolvers });  
server.applyMiddleware({ app });app.listen(3000, () => console.log('server started'));

Then when we go to /graphql in our browser, we see a UI to test our query.

To run the server, we run:

node index.js

We can test our server by running:

{  
  books {  
    title  
    author  
  }  
}

Then when we click the arrow button in the middle, we should get:

{  
  "data": {  
    "books": [  
      {  
        "title": "JavaScript for Dummies",  
        "author": "Jane Smith"  
      },  
      {  
        "title": "JavaScript Book",  
        "author": "Michael Smith"  
      }  
    ]  
  }  
}

as the response.

Conclusion

We created a simple Apollo GraphQL server with Express by installing the express and express-apollo-server packages.

Then we created the type definition by passing a string with the type definitions into the gql tag.

Once we did that, we created a resolver to return the response which is mapped from the query.

Then we run the server to make the query and return the data. We can test that by going to the /graphql page that comes with the Express Apollo server.

Categories
GraphQL JavaScript

Creating GraphQL Scalar Types with Express-GraphQL

With GraphQL, we can create scalar types as we do with create object types and other compound data types.

In this article, we’ll look at how to create scalar types with Express-GraphQL.

GraphQLScalarType

We can create a GraphQL scalar type with the GraphQLScalarType constructor. To create a scalar type, we have to give it a name, an optional description, and ways to serialize and parse the values.

The constructor takes an object with the following fields:

  • name — the name of the scalar type we want to define as a string
  • description — an optional string with the description of our type
  • serialize — a function that takes in a value parameter, which can be anything and then return something that we want to transform it to for transmission
  • parseValue — an optional function that takes a value parameter, which can be anything and then return the parsed value as we wish to
  • parseLiteral — a function that takes an abstract syntax tree object, which is the value of the literal, then we return something that we want to transform the value to.

Example

For example, we can write the following to create a scalar type and return it in the response:

const express = require('express');  
const graphqlHTTP = require('express-graphql');  
const graphql = require('graphql');const dateValue = (value) => {  
  if (value instanceof Date) {  
    return +value;  
  }  
}const DateType = new graphql.GraphQLScalarType({  
  name: 'Date',  
  serialize: dateValue,  
  parseValue: dateValue,  
  parseLiteral(ast) {  
    return dateValue(ast.value);  
  }  
});const queryType = new graphql.GraphQLObjectType({  
  name: 'Query',  
  fields: {  
    currentDate: {  
      type: DateType,  
      resolve: () => {  
        return new Date();  
      }  
    }  
  }  
});const schema = new graphql.GraphQLSchema({ query: queryType });const app = express();  
app.use('/graphql', graphqlHTTP({  
  schema: schema,  
  graphiql: true,  
}));app.listen(3000, () => console.log('server started'));

In the code above, we defined the dateValue function as follows:

const dateValue = (value) => {  
  if (value instanceof Date) {  
    return +value;  
  }  
}

In the function, we check if the value is created from the Date constructor, if it is, then we return the Date object converted to a timestamp.

Then we use it to create a new scalar type called Date as follows:

const DateType = new graphql.GraphQLScalarType({  
  name: 'Date',  
  serialize: dateValue,  
  parseValue: dateValue,  
  parseLiteral(ast) {  
    return dateValue(ast.value);  
  }  
});

We passed in the name, which is 'Date' . Then we have the serialize property with the dateValue to return the timestamp as the serialized version of the scalar type.

Likewise, we parse the Date object into a UNIX timestamp with the same function.

In the parseLiteral function, we pass in the value to the dateValue function to convert the Date object into a UNIX timestamp.

Then we create our query type so that we can return the timestamp response to the user as follows:

const queryType = new graphql.GraphQLObjectType({  
  name: 'Query',  
  fields: {  
    currentDate: {  
      type: DateType,  
      resolve: () => {  
        return new Date();  
      }  
    }  
  }  
});

We create the Query object type so that we can query it and then in the fields property, we return a currentDate field that’s of the Date scalar type that we defined earlier.

In the resolve method, we just return new Date() , which will automatically parsed into a UNIX timestamp in the response since that’s how we decided to serialize it in the dateValue function.

Then when we make a query as follows:

{  
  currentDate  
}

we get something like:

{  
  "data": {  
    "currentDate": 1579464244268  
  }  
}

where the currentDate is replaced with the current UNIX timestamp.

Conclusion

We can create a scalar type by using the GraphQLScalarType constructor.

To define one, we have to pass in functions to serialize and parse values as we wish to.

Categories
GraphQL JavaScript

More GraphQL Schemas and Types

GraphQL is a query language for our API and a server-side runtime for running queries by using a type system for our data.

In this article, we’ll look at some GraphQL data types including lists, required fields, interfaces, union types, and input types.

Lists and Non-Null

A non-null type can be created by using the ! type modifier.

With that added, it’ll make sure that we have to include the field when we’re making a query to the server.

The non-null modifier can be used for defining arguments for a field, which causes the GraphQL server to return a validation error if a null value is passed as that argument.

Lists work in a similar way. We can use square brackets to mark something as a list.

For example, we can use them together as follows:

type Person {  
  name: String!  
  addresses: [Address]!  
}

In the code above, we marked the name field as required and have the String type. Also, we have an addresses field which is a list of Address objects, and it’s also marked as required.

If we have something like:

myField: [String!]

This means that the list itself can be null, but myField can’t have any null members.

On the other hand, if we have:

myField: [String]!

then the list itself can’t be null, but it can contain null values.

We can nest any number of non-null and list modifiers according to our needs.

Interfaces

An interface is an abstract type that includes a certain set of fields that a type must include to implement the interface.

For example, we can create an interface as follows:

interface Person {  
  id: ID!  
  name: String!  
  friends: [Person]  
}

This means that a type that implements Person must have the exact fields as we listed above.

For example, we can create a type that implements the interface as follows:

type Employee implements Person{  
  id: ID!  
  name: String!  
  friends: [Person],  
  employeeId: String!  
}

In the code above, we have the Employee type that has all the fields above. We also have the employeeId string.

Therefore, we can use interfaces to ensure that a type has at least the fields and types that are listed in the interface.

To query something with various types that are implemented by an interface, we can use inline fragments as follows:

query Employee($id: ID!) {  
  employee(id: $id) {  
    name  
    ... on Employee {  
      employeeId  
    }  
  }  
}

Union types

Unio types are similar to interfaces, but they don’t get to specify any common fields between types.

We can define a union type with the union keyword as follows:

union Worker = Person | Employee

We’ll need to use a conditional fragment to be able to query any fields:

{  
  search(text: "an") {  
    __typename  
    ... on Person {  
      name  
    }  
    ... on Employee{  
      name  
      employeeId  
    }  
  }  
}

The __typename field is a String that indicates the type of the response object.

Input types

We can create input types to pass in whole objects into a request. For example, we can define an input type as follows:

input PersonInput {  
  firstName: String!  
  lastName: String!  
}

Then we can pass it into a mutation as follows:

mutation CreatePerson($person: PersonInput!) {  
  createReview(person: $person) {  
    firstName  
    lastName  
  }  
}

The fields on an input object can refer to input object types, but we can’t mix input and output types in our schema. Input object types also can’t have arguments in their fields.

Conclusion

To make sure a field isn’t null we can use the exclamation mark to mark it non-null.

We can also use square brackets to mark that something is a list.

To define a list of set fields for types, we can use interfaces to make sure all types that implement an interface have the fields listed.

Union types are useful for letting us combine common fields of types that implement the same interface and avoid repeating fields in queries.

We can use input types to pass in whole objects into a mutation.

Categories
Angular JavaScript TypeScript

Angular Animation Callbacks and Key Frames

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we look at animation callback and keyframes.

Animation Callbacks

The animation trigger emits callbacks when it starts and when it finishes.

For example, we can log the value of the event by writing the following code:

app.component.ts :

import { Component, HostBinding } from "@angular/core";  
import {  
  trigger,  
  transition,  
  style,  
  animate,  
  state  
} from "@angular/animations";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"],  
  animations: [  
    trigger("openClose", [  
      state(  
        "true",  
        style({ height: "200px", opacity: 1, backgroundColor: "yellow" })  
      ),  
      state(  
        "false",  
        style({ height: "100px", opacity: 0.5, backgroundColor: "green" })  
      ),  
      transition("false <=> true", animate(500))  
    ])  
  ]  
})  
export class AppComponent {  
  onAnimationEvent(event: AnimationEvent) {  
    console.log(event);  
  }  
}

app.component.html :

<button (click)="show = !show">Toggle</button>  
<div  
  [@openClose]="show ? true: false"  
  (@openClose.start)="onAnimationEvent($event)"  
  (@openClose.done)="onAnimationEvent($event)"  
>  
  {{show ? 'foo' : ''}}  
</div>

In the code above, we have:

(@openClose.start)="onAnimationEvent($event)"  
(@openClose.done)="onAnimationEvent($event)"

to call the onAnimationEvent callback when the animation begins and ends respectively.

Then in our onAnimationEvent callback, we log the content of the event parameter.

It’s useful for debugging since it provides information about the states and elements of the animation.

Keyframes

We can add keyframes to our animation to create animations that are more complex than 2 stage animations.

For example, we can write the following:

app.component.ts :

import { Component } from "@angular/core";  
import {  
  trigger,  
  transition,  
  style,  
  animate,    
  keyframes  
} from "@angular/animations";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"],  
  animations: [  
    trigger("openClose", [  
      transition('true <=> false', [  
        animate('2s', keyframes([  
          style({ backgroundColor: 'blue' }),  
          style({ backgroundColor: 'red' }),  
          style({ backgroundColor: 'orange' })  
        ]))  
    ])  
  ]  
})  
export class AppComponent {  
  onAnimationEvent(event: AnimationEvent) {  
    console.log(event);  
  }  
}

app.component.html :

<button (click)="show = !show">Toggle</button>  
<div [@openClose]="show ? true: false">  
  {{show ? 'foo' : 'bar'}}  
</div>

In the code above, we add keyframes with different styles in AppComponent .

They’ll run in the order that they’re listed for the forward state transition and reverse for the reverse state transition.

Then when we click Toggle, we’ll see the color changes as the text changes.

Offset

Keyframes include an offset that defines the point in the animation where each style change occurs.

Offsets are relative measures from zero to one. They mark the beginning and end of the animation.

These are optional. Offsets are automatically assigned when they’re omitted.

For example, we can assign offsets as follows:

app.component.ts :

import { Component } from "@angular/core";  
import {  
  trigger,  
  transition,  
  style,  
  animate,    
  keyframes  
} from "@angular/animations";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"],  
  animations: [  
    trigger("openClose", [  
      transition('true <=> false', [  
        animate('2s', keyframes([  
          style({ backgroundColor: 'blue', offset: 0 }),  
          style({ backgroundColor: 'red', offset: 0.6 }),  
          style({ backgroundColor: 'orange', offset: 1 })  
        ]))  
    ])  
  ]  
})  
export class AppComponent {  
  onAnimationEvent(event: AnimationEvent) {  
    console.log(event);  
  }  
}

app.component.html :

<button (click)="show = !show">Toggle</button>  
<div [@openClose]="show ? true: false">  
  {{show ? 'foo' : 'bar'}}  
</div>

In the code above, we added offset properties to our style argument objects to change the timing of the color changes.

The color changes should shift slightly in timing compared to before.

Keyframes with a Pulsation

We can use keyframes to create a pulse effect by defining styles at a specific offset throughout the animation.

To add them, we can change the opacity of the keyframes as follows:

app.component.ts :

import { Component } from "@angular/core";  
import {  
  trigger,  
  transition,  
  style,  
  animate,    
  keyframes  
} from "@angular/animations";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"],  
  animations: [  
    trigger("openClose", [  
      transition('true <=> false', [  
        animate('1s', keyframes ( [  
          style({ opacity: 0.1, offset: 0.1 }),  
          style({ opacity: 0.6, offset: 0.2 }),  
          style({ opacity: 1,   offset: 0.5 }),  
          style({ opacity: 0.2, offset: 0.7 })  
        ]))  
    ])  
  ]  
})  
export class AppComponent {  
  onAnimationEvent(event: AnimationEvent) {  
    console.log(event);  
  }  
}

app.component.html :

<button (click)="show = !show">Toggle</button>  
<div [@openClose]="show ? true: false">  
  {{show ? 'foo' : 'bar'}}  
</div>

In the code above, we have the style argument objects that have the opacity and offset properties.

The opacity difference will create a pulsating effect.

The offset will change the timing of the opacity changes.

Then when we click Toggle, we should see the pulsating effect.

Automatic Property Calculation with Wildcards

We can set CSS style properties to a wildcard to do automatic calculations.

For example, we can use wildcards as follows:

app.component.ts :

import { Component } from "@angular/core";  
import {  
  trigger,  
  transition,  
  style,  
  animate,  
  state  
} from "@angular/animations";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"],  
  animations: [  
    trigger("openClose", [  
      state("in", style({ height: "*" })),  
      transition("true => false", [  
        style({ height: "*", backgroundColor: "pink" }),  
        animate(250, style({ height: 0 }))  
      ]),  
      transition("false => true", [  
        style({ height: "*", backgroundColor: "yellow" }),  
        animate(250, style({ height: 0 }))  
      ])  
    ])  
  ]  
})  
export class AppComponent {  
  onAnimationEvent(event: AnimationEvent) {  
    console.log(event);  
  }  
}

app.component.html :

<button (click)="show = !show">Toggle</button>  
<div [@openClose]="show ? true: false">  
  {{show ? 'foo' : 'bar'}}  
</div>

In the code above, we set the height of the styles to a wildcard because we don’t want to set the height to a fixed height.

Then when we click Toggle, we see the color box grow and shrink as the animation runs.

Conclusion

We can add callbacks to our animation to debug our animations since we can log the values there.

To make more complex animations, we can use keyframes.

Offsets can be used to change the timing of the keyframes of the animation.

We can use wildcards to automatically set CSS style values.

Categories
Angular JavaScript TypeScript

Advanced Usage of the Angular HTTP Client

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we’ll look at how to make PUT and DELETE requests with the Angular HTTP Client and using HTTP interceptors.

Making a DELETE Request

We can use the delete method to make a DELETE request by passing in the request URL as the first argument and an request options object as the 2nd argument

For example, we can use it as follows:

app.component.ts :

import { Component } from "@angular/core";  
import { HttpClient, HttpHeaders } from "@angular/common/http";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  constructor(private http: HttpClient) { } ngOnInit() {  
    this.getPost();  
  } 

  getPost() {  
    const httpOptions = {  
      headers: new HttpHeaders({  
        "Content-Type": "application/json"  
      })  
    }; 

    this.http  
      .delete("https://jsonplaceholder.typicode.com/posts/1", httpOptions)  
      .subscribe(res => console.log(res));  
  }  
}

In the code above, we call the delete method with the URL and httpOptions .

Then we call subscribe to initiate the request. The subscribe callback’s parameter has the response content.

Making a PUT Request

A PUT request can be made with the put method. It’s similar to the post method except it makes a PUT request.

The first argument is the URL, the 2nd is the request body, and the 3rd argument is the request options object.

For example, we can write the following:

app.component.ts :

import { Component } from "@angular/core";  
import { HttpClient, HttpHeaders } from "@angular/common/http";  
import { Post } from "./post";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls:["./app.component.css"]  
})  
export class AppComponent {  
  constructor(private http: HttpClient) {}  

  ngOnInit() {  
    this.addPost();  
  } 

  addPost() {  
    const body = {  
      userId: 1,  
      title: "title",  
      body: "body"  
    }; 

    const httpOptions = {  
      headers: new HttpHeaders({  
        "Content-Type": "application/json"  
      })  
    }; 

    this.http  
      .put<Post>(  
        "https://jsonplaceholder.typicode.com/posts/",  
        body,  
        httpOptions  
      )  
      .subscribe(res => console.log(res));  
  }  
}

HTTP Interceptors

We can create and use HTTP interceptors to inspect and transform HTTP requests from our app to the server.

They can also be used to inspect and transform the server’s response on their way back to the app.

Multiple interceptors form a forward and backward chain of request/response handlers.

We can create and use our interceptor as follows:

http-req-interceptor.ts :

import { Injectable } from "@angular/core";  
import {  
  HttpEvent,  
  HttpInterceptor,  
  HttpHandler,  
  HttpRequest  
} from "@angular/common/http";
import { Observable } from "rxjs";

@Injectable()  
export class HttpReqInterceptor implements HttpInterceptor {  
  intercept(  
    req: HttpRequest<any>,  
    next: HttpHandler  
  ): Observable<HttpEvent<any>> {  
    return next.handle(req);  
  }  
}

app.module.ts :

import { BrowserModule } from "@angular/platform-browser";  
import { NgModule } from "@angular/core";  
import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http";  
import { AppComponent } from "./app.component";  
import { HttpReqInterceptor } from "./http-req-inteceptor";

@NgModule({  
  declarations: [AppComponent],  
  imports: [BrowserModule, HttpClientModule],  
  providers: [  
    { provide: HTTP_INTERCEPTORS, useClass: HttpReqInterceptor, multi: true }  
  ],  
  bootstrap: [AppComponent]  
})  
export class AppModule {}

In the code above, we created the HttpReqInterceptor class that extends the HttpInterceptor interface.

To implement the interface, we implement the intercept method which returns the observable returned by next.handle .

Then we can use it by adding the following:

{ provide: HTTP_INTERCEPTORS, useClass: HttpReqInterceptor, multi: true }

to the providers array in AppModule .

Interceptor Order

If we have interceptors A, B, and C provided in that order, then if we make an HTTP request, A runs, then B, then C.

When our app receives a response, it’ll run C first, then B, then A.

intercept and handle return HttpEvent<any> instead of HttpResponse<any> .

This is because interceptors examine and modify the response from next.handle .

Immutability

HttpRequest and HttpResponse instance properties are readonly , which makes them immutable.

This is good because requests may be retried several times. We don’t want the retry request to be modified before it’s retried.

Therefore, if we want to change the request, we have to clone it and then return next.handle with the cloned request passed in as follows:

http-req-inteceptor.ts :

import { Injectable } from "@angular/core";  
import {  
  HttpEvent,  
  HttpInterceptor,  
  HttpHandler,  
  HttpRequest  
} from "@angular/common/http";import { Observable } from "rxjs";

@Injectable()  
export class HttpReqInterceptor implements HttpInterceptor {  
  intercept(  
    req: HttpRequest<any>,  
    next: HttpHandler  
  ): Observable<HttpEvent<any>> {  
    const secureReq = req.clone({  
      url: req.url.replace("http://", "https://")  
    });  
    return next.handle(secureReq);  
  }  
}

In the code above, we modified all request URLs that started with http to start with https .

Modifying the Request Body

We can modify the request body as follows before sending it to the server:

http-req-interceptor.ts :

import { Injectable } from "@angular/core";  
import {  
  HttpEvent,  
  HttpInterceptor,  
  HttpHandler,  
  HttpRequest  
} from "@angular/common/http";import { Observable } from "rxjs";

@Injectable()  
export class HttpReqInterceptor implements HttpInterceptor {  
  intercept(  
    req: HttpRequest<any>,  
    next: HttpHandler  
  ): Observable<HttpEvent<any>> {  
    const body = req.body;  
    const newBody = { ...body, title: body.name.trim() };  
    const newReq = req.clone({ body: newBody });  
    return next.handle(newReq);  
  }  
}

In the code above, we copied the request body with:

const body = req.body;  
const newBody = { ...body, title: body.name.trim() };

Then we set the body of the request to the newBody by writing:

const newReq = req.clone({ body: newBody });

In the end, we returned the request observable.

We set the body to an empty object undefined or null to clear the request body in the example above.

Conclusion

We can make PUT and DELETE requests by calling the put and delete methods.

put takes the URL as the first argument, the request body as the 2nd argument, and the request options object as the last argument.

delete takes the URL as the first argument, and the request options object as the last argument.

To transform requests before sending it, we can create and user HTTP interceptors.

They can be chained and called in the same order they’re provided for making requests, and the reverse order when receiving responses.