Crea una cuenta o inicia sesi贸n

隆Contin煤a aprendiendo sin ning煤n costo! 脷nete y comienza a potenciar tu carrera

Scalars, filtros y queries avanzadas

4/23
Recursos

Aportes 18

Preguntas 7

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

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.

Para los pr贸ximos cursos seria bueno que hiciera todo paso a paso se entiende m谩s as铆, la mayor铆a de los videos de programaci贸n en platzi tienen ya archivos creados y no se si lo hacen para que el curso sea m谩s corto, pero la verdad le baja calidad y no se aprende como es debido, por eso prefiero los cursos de udemy en cuanto a programaci贸n ya que puedes encontrarlos de ese tipo paso a paso

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

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

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"
  }
}
Bueno, otro curso que no puedo aprender con 茅ste profesor porque no explica su c贸digo solo pasa por encima y que adivinemos...

Muy bien explicado, me gusta est谩 metodolog铆a porque no tengo que estar siguiendo el ritmo de profesor al escribir c贸digo ni estar pausando el v铆deo. As铆 me queda claro todo y si tengo alguna duda o quiero experimentar algo, lo hago en el c贸digo ya hecho.

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

Me gusto que pusiera como ejercicio completar el esquema y los resolvers, pero me molesta que no se vaya con m谩s calma explicando sus cambios, al final lo que va a servir para lo que sigue de su curso son sus cambios y solo saltarme al tag que est谩 usando no me parece una buena manera de aprender.

Es solo una opini贸n, no se lo tomen personal.

Espero y esto se pudiera mejorar, ya que es el segundo curso que tomo de el y esperar铆a que pudiera mejorar por que llego a un punto en donde no puedo continuar si no me paso a la versi贸n de sus tags.

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)
        },
    },
}

As铆 qued贸 mi c贸digo del reto anterior:

import { ApolloServer } from 'apollo-server';


// Query
const typeDefs = `

    type Avo {
        _id: String
        name: String!
        price: Float!
        image: String
    }

    type Query {
        getAvos: [Avo]
    }

    input avoInput {
        _id: String
        name: String!
        price: Float!
        image: String
    }

    type Mutation {
        createAvo(input: avoInput): Avo
    }
`

let avos = [
    {
        "_id": "1",
        "name": "Avo 1",
        "price": 12.2,
        "image": "https://avo.com/",
    },
    {
        "_id": "2",
        "name": "Avo 2",
        "price": 123,
        "image": "https://avo.com/",
    },
    {
        "_id": "2",
        "name": "Avo 3",
        "price": 12311,
        "image": "https://avo.com/",
    },
];


// Resolvers
const resolvers = {
    Query: {
        getAvos: () => avos,
    },
    Mutation: {
        createAvo: (root: any, {input }: any) => {
            avos.push(input);
            return input;
        }
    }
}

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

server.listen().then(({url}) => {console.log(`Listening on ${url}`)})

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.

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
}

Si su servidor no se reinicia autom谩ticamente cuando se cambia el archivo .graphql, posiblemente es por la configuraci贸n de nodemon y se tenga que a帽adir un archivo /api/nodemon.json con la siguiente configuraci贸n:

{
  "watch": ["src"],
  "ext": "ts graphql",
  "exec": "ts-node --transpile-only src/index.ts"
}