Scalars, filtros y queries avanzadas

4/23
Recursos

Aportes 12

Preguntas 4

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesi贸n.

Al ver un curso espero aprender cosas no a escuchar explicaciones de codigos y/o proyectos que ya estan todos desarrollados鈥 Cual seria el objetivo de este curso si solo me pongo a leer codigo
Para otros cursos mejor ponte a programar desde cero y explicar, no te pongas a explicar codigo que ya esta escrito 馃槂

Me gusta mucho la metodolog铆a para ense帽ar que usa este profesor.
Es dificil, pero genera un gran reto en cada clase

Me perdonaran pero que sentido tiene venir a una clase a leer el 30% del total del c贸digo agregado y ver al profesor copiar y pegar, no es que no quiera tomarme el tiempo de entender pero se trata de una clase

Por si alguien se pregunta de d贸nde sac贸 el profesor la definici贸n del scalar (al menos yo no la sab铆a, ni la entend铆a), la tom贸 de esta documentaci贸n de Apollo, creo que esta otra docu de GraphQL tambi茅n les resultar谩 煤til.

Despu茅s de 3 d铆as aprendiendo TypeScript correg铆 mi c贸digo basado en esta clase 馃槃 馃槃
Lo explicare paso a paso:


  • Divid铆 el c贸digo en una carpeta models la cual tiene el archivo schema.graphql y una resolvers con los resolvers.

  • El index.ts configure el context del apollo server para pasar la 鈥渄b鈥 (luego tendra sentido)

  • El schema.graphql tiene el modelo de la clase:

  • Dentro de resolvers/index.ts cree el objeto para el resolver de apollo server

  • Para configurar los queries y mutations cree sus propios archivos y el objeto context tiene toda la informaci贸n de la 鈥渄b鈥 que configure en la propiedad context del apollo server (ignoren el type de la l铆nea 3 xd)

  • Dentro de /resolvers/base estan algunos tipos usados en los queries y mutations y el resolver para el type Avocado o alg煤n otro type si llegara a crear otro

El unico problema que tuve fue este warning:

Fue muy complejo pero divertido programar todo eso, aprendi muchas cosas de TypeScript como los Utility Types, keyof, etc. Y muchas otras formas de configurar el resolver.
Repo de mi proyecto


Nunca pares de aprender

Les comparto el c贸digo del Mutation 15:40 -> Data completa del repo del profe

{
  "data": {
    "name": "Reed Avocado",
    "price": 1.18,
    "image": "/images/reed.jpg",
      "description":
        "Developed from a chance seedling found in 1948 by James S. Reed in California, this cultivar has large, round, green fruit with a smooth texture and dark, thick, glossy skin. Smooth and delicate, the flesh has a slightly nutty flavor. The skin ripens green. A Guatemalan type, it is hardy to 鈭1 掳C (30 掳F). Tree size is about 5 by 4 m (16.4 by 13.1 ft)",
      "shape": "Round",
      "hardiness": "鈭1 掳C",
      "taste": "Exquisite, is an avocado"
  }
}

Mi repo. Le agregare un tag de un antes y despu茅s de esta clase a ver que tal queda luego 馃槃
https://github.com/MiguelHG2351/platzi-node-prisma-graphql

Estructura del proyecto

馃洜 Repositorio Link
.

.
En mi caso, sigo la estructura de mi proyecto, dandole al directorio GraphQL la siguiente estructura:

graphql
 鈹斺攢猥 enums
 鈹斺攢猥 models
	 鈹斺攢猥 Account
		 鈹斺攢猥 Account.entity.ts
		 鈹斺攢猥 Account.model.ts
		 鈹斺攢猥 Account.schema.ts
 鈹斺攢猥 scalars
 鈹斺攢猥 index.ts

Donde en cada elemento:

// Account.entity.ts
export interface Account {
    id: number
    email: string
    password: string
}

export type Query = Pick<Account, 'id'>
export type Payload = Pick<Account, 'email' | 'password'>
// Account.model.ts
import Model from '@models/Model'

import { Account, Query, Payload } from './Account.entity'

import accounts from '@db/mocks/account.mock'

export default class AccountModel extends Model<Account, Query, Payload> {
    /**
     * @description Find an account by id.
     * @param {Query} {id} Account ID.
     * @returns {Account | undefined} Account */
    findUnique({ id }: Query): Account | undefined {
        return accounts.find((account) => account.id === id)
    }
    /**
     * @description Find pool of accounts.
     * @returns {Account[]} Array of accounts. */
    findMany(): Account[] {
        return accounts
    }
    /**
     * @description Create an account.
     * @returns {Account} */
    create(payload: Payload): Account {
        return {
            id: 1,
            ...payload,
        }
    }
}

// Account.schema.ts
import { gql } from 'apollo-server'

import { Query, Payload } from './Account.entity'
import AccountModel from './Account.model'

import Error from '@controllers/Error.controller'

const accountModel = new AccountModel()

export default {
    Schema: gql`
        type Account {
            id: ID!
            email: String!
            password: String!
        }

        input CreateAccount {
            email: String!
            password: String!
        }

        extend type Query {
            account(id: ID!): Account!
            accounts: [Account!]!
        }
    `,
    Query: {
        account: (_: any, query: Query) => {
            const account = accountModel.findUnique(query)
            if (!account) throw new Error('NOT_FOUND')
            return account
        },
        accounts: () => {
            return accountModel.findMany()
        },
    },
    Mutation: {
        createAccount: (_: any, payload: Payload) => {
            return accountModel.create(payload)
        },
    },
}

Schema Definition Language (SDL)

Especificaci贸n que define un schema y definirlo como una cadena.
.
Un schema define una colecci贸n de tipos y sus relaciones a trav茅s de types.
.
Cada relaci贸n define una unificaci贸n, lo que permite que los clientes puedan ver la informaci贸n disponible, organizada.
.

馃挕 Un SDL no es responsable de la localidad real de la informaci贸n y como es almacenada, es decir, se mantiene agn贸stica.

.

Esquemas y tipos

Dado el siguiente c贸digo:

type Character {
  name: String!
  appearsIn: [Episode!]!
}

Character representa un Object Type representando un modelo. Dicho modelo pose fields como name y appearsIn.
.
Cada atributo cuenta con una tipo scalar , nulleable o requerido !.
.
Los tipos Query son estructuras que definen puntos de entradas para operaciones de lectura.

type Query {
  books: [Book]
  authors: [Author]
}

Los tipos Mutation son estructuras que definen puntos de entradas para operaciones de escritura.

type Mutation {
  addBook(title: String, author: String): Book
}

Los tipos Input son estructuras que definen una jerarqu铆a de informaci贸n para argumentos.
.

input BlogPostContent {
  title: String
  body: String
  media: [MediaDetails!]
}

input MediaDetails {
  format: MediaFormat!
  url: String!
}

enum MediaFormat {
  IMAGE
  VIDEO
}

Uniones e Interfaces

Las uniones son definiciones de tipos utilizados para campos o lista de campos.

union SearchResult = Book | Author

type Book {
  title: String!
}

type Author {
  name: String!
}

type Query {

  search(contains: String): [SearchResult!]
}

Una interfaz especifica un conjunto de campos que m煤ltiples objetos pueden incluir.

interface Book {
  title: String!
  author: Author!
}

type Textbook implements Book {
  title: String! # Must be present
  author: Author! # Must be present
  courses: [Course!]!
}

type Query {
  books: [Book!] # Can include Textbook objects
}

Si un objeto implementa una interface, este debe incluir todos los campos de la interface.
.
Cuando se ocupa una interface como tipo de un capo, este puede incluir todos los objetos que implementan la interfaz.

Escalares

Por default, GraphQL incluye escalares por default tales como Int , Float, String, Boolean y ID.
.
Para definir un escalar, se necesita agregar al esquema la definici贸n scalar Date.
.
Despu茅s se necesita determinar sus interacciones mediante una instancia de la clase GraphQLScalarType . De esta instancia, en particular, se necesita la representaci贸n del valor y serialized/deserialized.

import dayjs from 'dayjs'
import { GraphQLScalarType, Kind } from 'graphql'

export default new GraphQLScalarType({
    name: 'Date',
    description: 'Date custom scalar type',
    serialize: (date) => dayjs(date as string).toJSON(),
    parseValue: (date) => dayjs(date as number),
    parseLiteral: (ast) =>
        ast.kind === Kind.INT ? dayjs(parseInt(ast.value, 10)) : null,
})

.
Cada inicializaci贸n define los siguientes m茅todos:

  • Serialize - m茅todo que convierte una representaci贸n de valor a un formato compatible en JSON
    .
  • parseValue - m茅todo que convierte un valor en JSON a una representaci贸n de valor enviado como args
    .
  • parseLiteral - m茅todo que convierte un valor en Abstract Syntax Tree (AST) a una representaci贸n de valor.

Para poder sacarle provecho a este curso hay que tener un conocimiento basico de typescript, apollo, prisma y graphql porque no te lleva paso a paso mientras crea el paso sino que te muestra codigo que ya existe

Vengo del futuro, si no les funciona la query para obtener un avocado, pueden usar algo como esto:

type GetOneAvocadoArgs = {
  id: string
}

const getOneAvocado = (
  parent: unknown,
  { id }: GetOneAvocadoArgs,
  context: unknown
): Avocado | null => {
  const avocado = avocados.find(avo => avo.id === id)

  return avocado ?? null
}