All Projects → arjunyel → Angular Spacex Graphql Codegen

arjunyel / Angular Spacex Graphql Codegen

Licence: unlicense

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to Angular Spacex Graphql Codegen

Smakosh.com
My personal website
Stars: ✭ 185 (-1.6%)
Mutual labels:  graphql
Graphql Engine Heroku
Blazing fast, instant realtime GraphQL APIs on Postgres with fine grained access control, also trigger webhooks on database events.
Stars: ✭ 188 (+0%)
Mutual labels:  graphql
React Imgpro
📷 Image Processing Component for React
Stars: ✭ 2,186 (+1062.77%)
Mutual labels:  graphql
Json To Simple Graphql Schema
Transforms JSON input into a GraphQL schema
Stars: ✭ 185 (-1.6%)
Mutual labels:  graphql
Gatsby Starter Morning Dew
🚀 A Gatsby theme/starter to build lightning-fast blog/websites
Stars: ✭ 186 (-1.06%)
Mutual labels:  graphql
Autoserver
Create a full-featured REST/GraphQL API from a configuration file
Stars: ✭ 188 (+0%)
Mutual labels:  graphql
Prisma Auth0 Example
Boilerplate Prisma Startup
Stars: ✭ 184 (-2.13%)
Mutual labels:  graphql
Json To Graphql
Create GraphQL schema from JSON files and APIs
Stars: ✭ 189 (+0.53%)
Mutual labels:  graphql
Cf Graphql
Generate a GraphQL schema out of your Contentful space
Stars: ✭ 187 (-0.53%)
Mutual labels:  graphql
Graphql.js
A Simple and Isomorphic GraphQL Client for JavaScript
Stars: ✭ 2,206 (+1073.4%)
Mutual labels:  graphql
Next React Graphql Apollo Hooks
React, Apollo, Next.js, GraphQL, Node.js, TypeScript high performance boilerplate with React hooks GraphQL implementation and automatic static type generation
Stars: ✭ 186 (-1.06%)
Mutual labels:  graphql
Fullstack
React/ApolloGraphQL/Node/Mongo demo written in Typescript
Stars: ✭ 12,653 (+6630.32%)
Mutual labels:  graphql
Blog Service
blog service @nestjs
Stars: ✭ 188 (+0%)
Mutual labels:  graphql
Graphql Ppx
GraphQL language primitives for ReScript/ReasonML written in ReasonML
Stars: ✭ 185 (-1.6%)
Mutual labels:  graphql
Next Ecommerce
⚡️ Quantum Ecommerce. Made with Next.js | GraphQL | Apollo Server | Apollo Client | SSR
Stars: ✭ 186 (-1.06%)
Mutual labels:  graphql
Hotchocolate
Welcome to the home of the Hot Chocolate GraphQL server for .NET, the Strawberry Shake GraphQL client for .NET and Banana Cake Pop the awesome Monaco based GraphQL IDE.
Stars: ✭ 3,009 (+1500.53%)
Mutual labels:  graphql
Graphql Spqr Spring Boot Starter
Spring Boot 2 starter powered by GraphQL SPQR
Stars: ✭ 187 (-0.53%)
Mutual labels:  graphql
Koa Passport Mongoose Graphql
Koa 2 server with Passport + Mongoose + GraphQL
Stars: ✭ 190 (+1.06%)
Mutual labels:  graphql
Pronote Api
(Tout langage) API compatible Pronote 2020/2021
Stars: ✭ 186 (-1.06%)
Mutual labels:  graphql
Tipe
🎉 Next Generation API-first CMS for developers. Generate an API-first CMS from a GraphQL schema with offline prototyping and an inline editor
Stars: ✭ 2,157 (+1047.34%)
Mutual labels:  graphql

Angular Spacex Graphql Codegen

Mission

Our goal is to make an Angular app with a list of the past SpaceX launches along with an associated details page. Data is provided via the SpaceX GraphQL API and Angular services are generated via GraphQL Code Generator. We use Apollo Angular to access data from the frontend. The API is free so please be nice and don't abuse it.

End Result

List view

Details view

Steps

  1. Generate a new angular application with routing

    ng new angular-spacex-graphql-codegen --routing=true --style=css
    

    Make sure to delete the default template in src/app/app.component.html

  2. Install the Apollo VS Code plugin and in the root of the project add apollo.config.js

    module.exports = {
      client: {
        service: {
          name: 'angular-spacex-graphql-codegen',
          url: 'https://api.spacex.land/graphql/'
        }
      }
    };
    

    This points the extension at the SpaceX GraphQL API so we get autocomplete, type information, and other cool features in GraphQL files. You may need to restart VS Code.

  3. Generate our two components:

    ng g component launch-list --changeDetection=OnPush
    
    ng g component launch-details --changeDetection=OnPush
    

    Because our generated services use observables we choose OnPush change detection for the best performance.

  4. In src/app/app-routing.module.ts we setup the routing:

    import { LaunchListComponent } from './launch-list/launch-list.component';
    import { LaunchDetailsComponent } from './launch-details/launch-details.component';
    
    const routes: Routes = [
      {
        path: '',
        component: LaunchListComponent
      },
      {
        path: ':id',
        component: LaunchDetailsComponent
      }
    ];
    
  5. Each component will have its own data requirments so we co-locate our graphql query files next to them

    # src/app/launch-list/launch-list.graphql
    
    query pastLaunchesList($limit: Int!) {
      launchesPast(limit: $limit) {
        id
        mission_name
        links {
          flickr_images
          mission_patch_small
        }
        rocket {
          rocket_name
        }
        launch_date_utc
      }
    }
    
    # src/app/launch-details/launch-details.graphql
    
    query launchDetails($id: ID!) {
      launch(id: $id) {
        id
        mission_name
        details
        links {
          flickr_images
          mission_patch
        }
      }
    }
    

    Note the first line: query launchDetails($id: ID!) When we generate the Angular service the query name is turned into PascalCase and GQL is appended to the end, so the service name for the launch details would be LaunchDetailsGQL. Also in the first line we define any variables we'll need to pass into the query. Please note it's import to include id in the query return so apollo can cache the data.

  6. We add Apollo Angular to our app with ng add apollo-angular. In src/app/graphql.module.ts we set our API url const uri = 'https://api.spacex.land/graphql/';.

  7. Install Graphql Code Generator and the needed plugins npm i --save-dev @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-apollo-angular @graphql-codegen/typescript-operations

  8. In the root of the project create a codegen.yml file:

    # Where to get schema data
    schema:
      - https://api.spacex.land/graphql/
    # The client side queries to turn into services
    documents:
      - src/**/*.graphql
    # Where to output the services and the list of plugins
    generates:
      ./src/app/services/spacexGraphql.service.ts:
        plugins:
          - typescript
          - typescript-operations
          - typescript-apollo-angular
    
  9. In package.json add a script "codegen": "gql-gen" then npm run codegen to generate the Angular Services.

  10. To make it look nice we add Angular Material ng add @angular/material then in the app.module.ts we import the card module and add to the imports array: import { MatCardModule } from '@angular/material/card';

  11. Lets start with the list of past launches displayed on the screen:

    import { map } from 'rxjs/operators';
    import { PastLaunchesListGQL } from '../services/spacexGraphql.service';
    
    export class LaunchListComponent {
      constructor(private readonly pastLaunchesService: PastLaunchesListGQL) {}
    
      // Please be careful to not fetch too much, but this amount lets us see lazy loading imgs in action
      pastLaunches$ = this.pastLaunchesService
        .fetch({ limit: 30 })
        // Here we extract our query data, we can also get info like errors or loading state from res
        .pipe(map((res) => res.data.launchesPast));
    }
    
    <ng-container *ngIf="pastLaunches$ | async as pastLaunches">
      <main>
        <section class="container">
          <mat-card
            *ngFor="let launch of pastLaunches"
            [routerLink]="['/', launch.id]"
          >
            <mat-card-header>
              <img
                height="50"
                width="50"
                mat-card-avatar
                loading="lazy"
                [src]="launch.links.mission_patch_small"
                alt="Mission patch of {{ launch.mission_name }}"
              />
              <mat-card-title>{{ launch.mission_name }}</mat-card-title>
              <mat-card-subtitle
                >{{ launch.rocket.rocket_name }}</mat-card-subtitle
              >
            </mat-card-header>
            <img
              height="300"
              width="300"
              mat-card-image
              loading="lazy"
              [src]="launch.links.flickr_images[0]"
              alt="Photo of {{ launch.mission_name }}"
            />
          </mat-card>
        </section>
      </main>
    </ng-container>
    

    Notice the cool addition of lazy loading images, if you emulate a mobile device in Chrome and fetch enough launches you should see the images lazy load while you scroll!

    To make it look nice we add CSS Grid

    .container {
      padding-top: 20px;
      display: grid;
      grid-gap: 30px;
      grid-template-columns: repeat(auto-fill, 350px);
      justify-content: center;
    }
    
    .mat-card {
      cursor: pointer;
    }
    
  12. Next we make the details page for a launch, we get the id from the route params and pass that to our service

    import { ActivatedRoute } from '@angular/router';
    import { map, switchMap } from 'rxjs/operators';
    import { LaunchDetailsGQL } from '../services/spacexGraphql.service';
    
    export class LaunchDetailsComponent {
      constructor(
        private readonly route: ActivatedRoute,
        private readonly launchDetailsService: LaunchDetailsGQL
      ) {}
    
      launchDetails$ = this.route.paramMap.pipe(
        map((params) => params.get('id') as string),
        switchMap((id) => this.launchDetailsService.fetch({ id })),
        map((res) => res.data.launch)
      );
    }
    

    The HTML looks very similar to the list of launches

    <ng-container *ngIf="launchDetails$ | async as launchDetails">
      <section style="padding-top: 20px;">
        <mat-card style="width: 400px; margin: auto;">
          <mat-card-header>
            <mat-card-title>{{ launchDetails.mission_name }}</mat-card-title>
          </mat-card-header>
          <img
            height="256"
            width="256"
            mat-card-image
            [src]="launchDetails.links.mission_patch"
            alt="Mission patch of {{ launchDetails.mission_name }}"
          />
          <mat-card-content>
            <p>{{ launchDetails.details }}</p>
          </mat-card-content>
        </mat-card>
      </section>
      <section class="photo-grid">
        <img
          *ngFor="let pic of launchDetails.links.flickr_images"
          [src]="pic"
          alt="Picture of {{ launchDetails.mission_name }}"
          height="300"
          width="300"
          loading="lazy"
        />
      </section>
    </ng-container>
    

    Finally we add CSS Grid for the pictures

    .photo-grid {
      padding-top: 30px;
      display: grid;
      grid-gap: 10px;
      grid-template-columns: repeat(auto-fill, 300px);
      justify-content: center;
    }
    
  13. npm start, navigate to http://localhost:4200/, and it should work!

Extra Credit: Relative launch times

Thanks to the new builtin relative time formating in V8, we can add launched x days ago

  1. Generate the pipe: ng g pipe relative-time --module=app.module --flat=false

  2. The pipe takes in the UTC time and returns a formatted string

    import { Pipe, PipeTransform } from '@angular/core';
    
    const milliSecondsInDay = 1000 * 3600 * 24;
    
    // Cast as any because typescript typing haven't updated yet
    const rtf = new (Intl as any).RelativeTimeFormat('en');
    
    @Pipe({
      name: 'relativeTime'
    })
    export class RelativeTimePipe implements PipeTransform {
      transform(utcTime: string): string {
        const diffInMillicseconds =
          new Date(utcTime).getTime() - new Date().getTime();
        const diffInDays = Math.round(diffInMillicseconds / milliSecondsInDay);
        return rtf.format(diffInDays, 'day');
      }
    }
    
  3. Add the pipe to our launch card in src/app/launch-list/launch-list.component.html

    <mat-card-subtitle
      >{{ launch.rocket.rocket_name }} - launched {{ launch.launch_date_utc |
      relativeTime }}</mat-card-subtitle
    >
    
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].