Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GraphQL basics with the Apollo Client

GraphQL basics with the Apollo Client

fr0gM4ch1n3

November 26, 2018
Tweet

More Decks by fr0gM4ch1n3

Other Decks in Programming

Transcript

  1. Angular Meetup
 Leipzig I can see at least 15 components

    on this page: • The Header component, which includes the following list of components: ProfileImage, BackgroundImage, TweetCount, FollowingCount, FollowersCount, LikesCount, and ListsCount • The Sidebar component, which includes the following list of components: UserInfo, FollowersYouKnow, UserMedia, and MediaItem. • The TweetList component, which is a list of Tweet components.
  2. Angular Meetup
 Leipzig 1. GraphQL Basic
 What?, Why? and How?

    - an overview over the language 2. Apollo Client
 Installation, run queries and mutation in Angular 3. Mocking
 Test your application! What's the talk about?
  3. The idea Describe your data type Project { name: String

    tagline: String contributors: [User] } Ask for what you want { project(name: "GraphQL") { tagline } } Get predictable results { "project": { "tagline": "A query language for APIs" } }
  4. Why you should use GraphQL ? •Versioning: To avoid multiple

    versioning of your rest API. •Ask for what you need: Client has a provision to ask only those fields which they needs. There would be no handling on server side specific to the platform. •Get many API’s response in single request: Client has to call one query to get data from multiple rest API’s.
  5. Github GraphQL type Launch { id: ID! site: String mission:

    Mission rocket: Rocket isBooked: Boolean! } type Rocket { id: ID! name: String type: String } type User { id: ID! email: String! trips: [Launch]! } type Mission { name: String missionPatch(size: PatchSize): String } enum PatchSize { SMALL LARGE }
  6. Scalar types • Int: A signed 32‐bit integer. • Float:

    A signed double-precision floating-point value. • String: A UTF‐8 character sequence. •Boolean: true or false. • ID: The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache. The ID type is serialized in the same way as a String; however, defining it as an ID signifies that it is not intended to be human‐readable. In most GraphQL service implementations, there is also a way to specify custom scalar types. For example, we could define a Date type: scalar Date
  7. Enumeration types enum Episode { NEWHOPE EMPIRE JEDI } Also

    called Enums, enumeration types are a special kind of scalar that is restricted to a particular set of allowed values. • Validate that any arguments of this type are one of the allowed values • Communicate through the type system that a field will always be one of a finite set of values
  8. Lists and Non-Null type Character { name: String! appearsIn: [Episode]!

    } myField: [String!] myField: null // valid myField: [] // valid myField: ['a', 'b'] // valid myField: ['a', null, 'b'] // error myField: [String]! myField: null // error myField: [] // valid myField: ['a', 'b'] // valid myField: ['a', null, 'b'] // valid This means that the list itself can be null, but it can't have any null members This means that the list itself cannot be null, but it can contain null values
  9. Input Input types look exactly the same as regular object

    types, but with the keyword input instead of type input ReviewInput { stars: Int! commentary: String } mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars commentary } } { "ep": "JEDI", "review": { "stars": 5, "commentary": "This is a great movie!" } }
  10. Installation with Angular Schematics To start using Apollo Angular simply

    run: ng add apollo-angular If you want to setup Apollo without the help of Angular Schematics, just follow the few steps from the documentation: www.apollographql.com/docs/angular/basics/setup.html#without-schematics
  11. Network layer (Apollo Link) A pluggable network interface layer, which

    can let you configure how queries are sent over HTTP, or replace the whole network part with something completely custom, like a websocket transport, mocked server data, or anything else you can imagine import { HttpClientModule } from '@angular/common/http'; import { ApolloModule, Apollo } from 'apollo-angular'; import { HttpLinkModule, HttpLink } from 'apollo-angular-link-http'; @NgModule({ imports: [ HttpClientModule, ApolloModule, HttpLinkModule ] }) class AppModule { constructor( apollo: Apollo, httpLink: HttpLink ) { const link = httpLink.create({ uri: 'https://example.com/graphql' }); apollo.create({ link, // other options like cache }); } }
  12. Middleware/Afterware Middlewares are used to inspect and modify every request

    made over the link and afterware runs after a request has been made, that is when a response is going to get processed @NgModule({ ... }) class AppModule { constructor( apollo: Apollo, httpLink: HttpLink ) { const http = httpLink.create({ uri: '/graphql' }); const authMiddleware = new ApolloLink((operation, forward) => { operation.setContext({ headers: new HttpHeaders() .set('Authorization', localStorage.getItem('token')) }); return forward(operation); }); apollo.create({ link: concat(authMiddleware, http), }); } }
  13. Query How to fetch data with Query components Fetching data

    in a simple, predictable way is one of the core features of Apollo Client 1.When the Query component mounts, Apollo Client creates an observable for our query. Our component subscribes to the result of the query via the Apollo Client cache. 2.First, we try to load the query result from the Apollo cache. If it’s not in there, we send the request to the server. 3.Once the data comes back, we normalize it and store it in the Apollo cache. Since the Query component subscribes to the result, it updates with the data reactively.
  14. Query ngOnInit() { this.querySubscription = this.apollo.watchQuery<any>({ query: gql` query CurrentUserForProfile

    { currentUser { login avatar_url } }` }) .valueChanges .subscribe(({ data, loading }) => { this.loading = loading; this.currentUser = data.currentUser; }); } ngOnDestroy() { this.querySubscription.unsubscribe(); }
  15. Query - options context any Context to be passed to

    link execution chain errorPolicy "none" | "ignore" | "all" Specifies the ErrorPolicy to be used for this query fetchPolicy "cache-first" | "cache-and-network" | "network-only" | "cache-only" | "no-cache" | "standby" Specifies the FetchPolicy to be used for this query fetchResults any Whether or not to fetch results metadata any Arbitrary metadata stored in the store with this query. Designed for debugging, developer tools, etc. notifyOnNetworkStatusChange any Whether or not updates to the network status should trigger next on the observer of this query pollInterval any The time interval (in milliseconds) on which this query should be refetched from the server. query DocumentNode A GraphQL document that consists of a single query to be sent down to the server. variables TVariables A map going from variable name to variable value, where the variables are used within the GraphQL query.
  16. Query context query() middleware link afterware response processing variables new

    ApolloLink((operation, forward) => { const context = operation.getContext(); operation.setContext({ ...context }); return forward(operation); });
  17. Error policies Valid errorPolicy values are: • none: This is

    the default value where we treat GraphQL errors as runtime errors. Apollo will discard any data that came back with the request and render your component with an error prop. • ignore: Much like none, this causes Apollo to ignore any data from your server, but it also won’t update your UI aside from setting the loading state back to false. • all: Selecting all means you want to be notified any time there are any GraphQL errors. It will render your component with any data from the request and any errors with their information. It is particularly helpful for server side rendering so your UI always shows something
  18. Mutations how to update data with Mutation components Now that

    we’ve learned how to fetch data with Apollo Client, what happens when we need to update that data?
  19. Mutations submit() { this.apollo.mutate({ mutation: gql` mutation submitRepository($repoFullName: String!) {

    submitRepository(repoFullName: $repoFullName) { createdAt } }`, variables: { repoFullName: 'apollographql/apollo-client' } }).subscribe(); }
  20. Optimistic UI Sometimes your client code can easily predict the

    result of the mutation, if it succeeds, even before the server responds with the result. giving the user the experience of a snappy UI
  21. Optimistic UI submit({ repoFullName, commentContent }) { this.apollo.mutate({ mutation: gql`

    mutation submitComment($repoFullName: String!, $commentContent: String!) { submitComment(repoFullName: $repoFullName, commentContent: $commentContent) { postedBy { login html_url } createdAt content } }`, variables: { repoFullName, commentContent }, optimisticResponse: { __typename: 'Mutation', submitComment: { __typename: 'Comment', postedBy: this.currentUser, createdAt: +new Date, content: commentContent, }, }, }).subscribe(); }
  22. Default mock Mock your GraphQL data based on a schema

    The strongly-typed nature of a GraphQL API lends itself extremely well to mocking. import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools'; import { graphql } from 'graphql'; // Fill this in with the schema string const schemaString = `...`; // Make a GraphQL schema with no resolvers const schema = makeExecutableSchema({ typeDefs: schemaString }); // Add mocks, modifies schema in place addMockFunctionsToSchema({ schema }); const query = ` query tasksForUser { user(id: 6) { id, name } }`; graphql(schema, query).then((result) => console.log('Got result', result));
  23. Customizing mocks This is where the mocks option comes in,

    it’s an object that describes your desired mocking logic. This is similar to the resolverMap in makeExecutableSchema, but has a few extra features aimed at mocking. It allows you to specify functions that are called for specific types in the schema, for example: { Int: () => 6, Float: () => 22.1, String: () => 'Hello', } You can also use this to describe object types, and the fields can be functions too: { Person: () => ({ name: casual.name, age: () => casual.integer(0, 120), }), }
  24. Using MockList in resolvers In more complex schemas, MockList is

    helpful for randomizing the number of entries returned in lists. { Person: () => ({ // a list of length between 2 and 6 (inclusive) friends: () => new MockList([2, 6]), // a list of three lists of two items: [[1, 1], [2, 2], [3, 3]] listOfLists: () => new MockList(3, () => new MockList(2)), }), } You can also use this to describe object types, and the fields can be functions too: { Person: () => ({ name: casual.name, age: () => casual.integer(0, 120), }), }
  25. Angular Meetup
 Leipzig query ask($q: String!) { question(q: $q) {

    answer } } github.com/fr0gM4ch1n3
 goo.gl/t2Sw69 Angular Meetup
 Leipzig