GroceriStar / playing-with-graphql

4 stars 4 forks source link

[GraphQL Basics course] [Main Task] [Sanchit] #7

Open atherdon opened 6 years ago

atherdon commented 6 years ago

Please start by reading the documentation, related to GraphQL: https://www.howtographql.com/ After reading each chapter - please briefly explain to me here what did you learn from it. Format(example):

Chapter 1: Intro (https://graphql.org/learn/)

"It's covering the basics of graphql" Questions: "How i can run it at my local PC"?


@sanchit94 - it's your task

sanchit94 commented 6 years ago

Okay, working on it! :)

atherdon commented 6 years ago

As you more familiar with our github workflow, please start reading first chapters asap and put here your progress. I think this will motivate our other team members to start a race. just a little competition does not harm, right? let's this will be our secret :)

sanchit94 commented 6 years ago

Please add me as a collaborator to this one @atherdon. For now I have forked this repo.

sanchit94 commented 6 years ago

@atherdon Okay so last night I learnt a lot about GraphQL, how it differs from the conventional RESTful APIs and some basic concepts of GraphQL. Basically it provides a single end-point which have ability to handle resource, contrary to REST which just hands over data from the resource and has multiple end-points. To use GraphQL, we need to define a Schemafirst, which is the raw structure in which data is stored. We also need a resolver function to maybe tell GraphQL how to fetch data, but that is not very clear with my current understanding.

sanchit94 commented 6 years ago

I have added a file server.js and was able to run in on command line by doing node server.js. For setting the project up, I used this [https://graphql.org/graphql-js/]

atherdon commented 6 years ago

please follow this link: https://github.com/GroceriStar/playing-with-graphql/invitations

Please hold on with an actual coding part. I mean at first i want to understand that you know main features and basics.

then we'll build some sort of pseudo-code in graphql schemas in order to practice it and discuss database improvements. main feature in GraphQL that you can easily extend the database - this is what hold my project back with REST API approach.

we have at least few databases and i prepare some plan so we actually will not just replicate logic of our current API servers, but we also will extend and update it. Some details please read here: https://medium.com/groceristar/chickenkyiv-database-logic-intro-part-1-b2c449d92aa3 https://medium.com/groceristar/chickenkyiv-database-logic-simple-samples-part-2-1ee3ccc6b3d https://medium.com/groceristar/chicken-kyiv-recipe-db-schema-part3-b80f33ec5d96

sanchit94 commented 6 years ago

@atherdon Thanks for providing me some perspective over the project, and yes I too realized that getting the basics of this is important. Specially for me because I have not worked much with APIs or back-end.

atherdon commented 6 years ago

i adore your pro-activity - don't want to loose it. But let's strict to main plan. this will be also more easy for me to follow your progress. So please check description of this task again - and try to explain to me for each sections at graph-ql intro what do you learn. this will raise a discussion between you and me, and we'll be able to start actual work at graphQl schema. when it'll looks cool - we'll start to test it.

Because actually - we have everything for it. We have a mongodb, we have imported data to it. so only schemas holding us back.

Btw, can you move that links to readme(please separate them from trash links that i store there), so other developers will have access to them too

atherdon commented 6 years ago
"url": "mongodb://heroku_p3w65n77:h3ab8q3uaqdk7tjrauhbl7dd6r@ds235065.mlab.com:35065/heroku_p3w65n77",
"name": "groceryDS",

"searchDS": { "url": "mongodb://heroku_ghbnqks1:eb8kogbcofqvkh13d6ccep825l@ds139994.mlab.com:39994/heroku_ghbnqks1",


"recipeDS": {
"url": "mongodb://heroku_p0dxgncb:gl2rr2bi235aoqfdojelqspjn1@ds147052.mlab.com:47052/heroku_p0dxgncb",


This is links to our mongo databases - please move them to readme too

sanchit94 commented 6 years ago

This chapter talks about how GraphQL service is created. Basically we first define types and then fields on those types. Also the datatype on each field is specified here. We also provide functions for each field on each type so that we can retrieve that data(, or do something with it). It also describes how to send a query to receive data, which is very simple and flexible way to do so.

atherdon commented 6 years ago

which chapter?

atherdon commented 6 years ago

please follow this template:

Chapter 1: Intro (https://graphql.org/learn/)

"This chapter talks about how GraphQL service is created. Basically we first define types and then fields on those types. Also the datatype on each field is specified here. We also provide functions for each field on each type so that we can retrieve that data(, or do something with it). It also describes how to send a query to receive data, which is very simple and flexible way to do so."

sanchit94 commented 6 years ago

Chapter 2: Queries and Mutation (https://graphql.org/learn/queries/)

  1. Query: Learnt how to structure query in GraphQL. In a query we can traverse our data and specify the field whose data we need, and the response is very similar to our query(, it is the query with the required data). We can ask for any field types, including Objects too, and we can go inside them by using brackets{ } and specify the required fields.
  2. Arguments: We can also pass arguments in the query for a field, to declaratively fetch data that is required.
  3. Aliases: Used for querying the same field with different arguments. Quite clear with the example there.
  4. Fragments: Cool feature, for modularising the query. Construct a set of fields, and then you can pass them into your query by ...fragmentName.
  5. Operation types: Any action is an operation. Operation can be of types query, mutation and subscription. Operations have types and name.
  6. Variables: variables can be also defined, for passing dynamic arguments in an operation. Variables can also be assigned default values.
  7. Directives: Used for dynamically manipulating the structure of the query. Like you can include or exclude some field by adding conditional statement on variables.
  8. Mutation: This is operation type for modifying data on the server. Cool thing is that you can query from the same data that you mutated. One thing is not clear however, in the example: mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars commentary } } Shouldn't it be something like: mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { review { stars commentary } } } Anyways I think things will get clear as I move on with it.
  9. Inline Fragments: Useful for querying when we do not know the type that is going to return. We can ask for specific fields based on the types of the returned data.
  10. Meta Fields: __typename can be used to determine to the type of the returned data, which can then be used to select what we want from the data.
atherdon commented 6 years ago

@sanchit94 perfect!

atherdon commented 6 years ago

please move this links to readme too: we have at least few databases and i prepare some plan so we actually will not just replicate logic of our current API servers, but we also will extend and update it. Some details please read here: https://medium.com/groceristar/chickenkyiv-database-logic-intro-part-1-b2c449d92aa3 https://medium.com/groceristar/chickenkyiv-database-logic-simple-samples-part-2-1ee3ccc6b3d https://medium.com/groceristar/chicken-kyiv-recipe-db-schema-part3-b80f33ec5d96


I think you saw this schemes, but i'll put it here, please move them to our readme too https://chickenkyiv.gitbook.io/documentation/database-schemes

https://github.com/ChickenKyiv/database-visuals

https://github.com/ChickenKyiv/database-visuals/tree/master/groceristar/models https://github.com/ChickenKyiv/database-visuals/tree/master/rapi/models https://github.com/ChickenKyiv/database-visuals/tree/master/recipeSearchAPI/models

sanchit94 commented 6 years ago

Done! 👍

sanchit94 commented 6 years ago

Chapter 3: Schemas and Types (https://graphql.org/learn/schema/)

  1. Type System: GraphQL has a strongly typed system, and we explicitly define types on each fieldof the objectin the schema definition. Types can be defined as in Object types using the type keyword, or they can be built-in scalar types. By this, we can have an idea of what to expect when a query is made. Types are also needed for validation of the query.
  2. Type Language: GraphQL has a uniques SDL(Schema Description Language) for describing schema of the GraphQL service.
  3. Object types and fields: An object type can have fields inside it, where each field can have a scalar type as it's type or another object type as it's type. Basically this is the way of implementing relational databases.
  4. Arguments: Every GraphQL field can have multiplearguments``, but they need to be explicitly passed by name. If an argument is optional we can assign a default value to it.
  5. Query and Mutation types: Every service has a query type which defines the entry-point for the GraphQL query. It may or may not have a mutation type. Defined using typekeyword. Question: Can I only query data of fields for which I have a query type?
  6. Scalar types: These are the leaves of the query, the fields that have these types do not have a sub-field. GraphQL has following scalar types: Int, String, Float, Boolean, ID. We can also specify custom scalar types, using scalarkeyword by doing scalar typeName
  7. Enumeration types: Special types of scalars where you can define a set of allowed values. Anything other than that will be an error during validation We can use enum keyword to define an 'enum'.
  8. Lists and Non-Null: While defining the type on a field, we can also apply type modifiers to extend our type. We can do String! to make the string type non-nullable. Once ! is added to the type, the server always expects a non-null value from that field. Second type modifier is List, where we can mark a field to return a list(kind of array) of values by wrapping [ ] around the type name. Both type modifiers can be flexibly combined according to need. Like we can do Numbers : [Int!] to indicate the Numbers field is a list of Int values, where each entry in the list is a non-null object. Although the list can be null itself. Numbers: [Int]! means the list is non-null, but a member of a list can be null. Numbers : [Int!]! means neither the list nor any member on the list is null.
  9. Interfaces: Interface is an abstract type, which includes a list of fields that an object type must include if it implements that interface, while that object type can have additional fields too. Similar to inheritance. When a type inherits from an interface, then the fields on the interface can be directly accessed, but the object-specific fields must be accessed by using in-line fragment.
  10. Union types: A type whose equivalent is an OR of specified types. This means an object of Union types can be either of the types in the description. For e.g. union Breakfast = Sandwiches | Omelet | Oats means that the union type Breakfast can be either of the types Sandwiches, Omelet or Oats. When querying union types, we should always use in-line fragments for each type(Sandwiches, Omelet, Oats) so that there is no error.
  11. Input types: We can pass complex objects as type to a field. For this we first need to create those objects using the input keyword. Then we can start passing them. Useful for mutations, where we pass these input types to the object, we can even pass them as variables. Pretty cool! :)
sanchit94 commented 6 years ago

Chapter 4: Validation(https://graphql.org/learn/validation/)

Validation is done using type system to determine whether a query is valid or not. So there are some rules that we need to follow. There are a few rules that are mentioned in the documentation:

  1. A fragment cannot refer to itself: As this would create a cycle, sort of recurrencebut there is no exit from it. So doing this will lead to an invalid query. For e.g.
    
    food {  
    ...details
    sameCuisine {
            ...details
            sameCuisine {
                  ...details
                 }
          }
    }

fragment details on foodItems { name cuisine }

This valid query, but if we try to implement the same using a fragment like

fragment details on foodItems { name cuisine ...details }


then it is invalid, as a fragment is calling itself.

2. When querying `fields`, only query for `fields` that are present in that `type`: Self explanatory, if we search for a field that is not present in the type, then it will be an error.

3. If the query returns something other than a `scalar `or `enum`, like an object type, then we need to specify which `fields` we want from that object. If we fail to do so the query is **invalid**. Question: What is the best practice in cases we need info of all fields? Do we make an enum?

4. If a field is `scalar`, we cannot query any fields inside it.

5. If our type `implements` an `interface`, then we can directly query only the fields on the `interface`. For querying **type-specific fields**, we can either use `inline fragments` or create a `fragment` on the type.
sanchit94 commented 6 years ago

Chapter 5: Execution (https://graphql.org/learn/execution/)

GraphQL query is executed after Validation which resolves to a JSON response, generally. Each field in a query has a corresponding resolver method which is a function that tells the service how to handle the query. This means it returns the type that is expected, and if that type is a scalartype, it would return the value. This completes the execution. A query always ends at the scalar type.

Root fields and resolver: Root type is the top level of the query. In the example given in the documentation, the root query has a resolver function human, which takes four arguments:

  1. obj: The previous object, which we have to enter in order to resolve the query. This is not need for root resolver function.
  2. args: The argument provided, for e.g. id, or name.
  3. context: Haven't got much idea what this is, but I think we will get to know more about the details of this as we move along. Maybe it contains methods to fetch data, like getHumantById.
  4. info: Containing field specific information and schema details.

Asynchronous Resolvers: The query does not always return data, but it returns a Promise, which can be passed around as a token even if we do not have the value yet, in hope that when the Promise is fulfilled, it will provide the data. During execution GraphQL waits for the Promises to resolve(or be rejected).

Trivial Resolvers: Trivial resolver is one that simply fetched the value of the field. Some libraries let us omit these trivial resolvers and do this for us by default.

Scalar Coercion: GraphQL can use scalars(or numbers) internally to store values of some objects. Once the query is made, the scalar is returned and the corresponding value to this scalar that is mapped can be returned.

List Resolvers: When a field type is a list, then GraphQL will return a list of Promises on that.

Producing the result: As the fields are resolved, the result is displayed in form of key-value pair(JSON) which looks like the query we requested.

atherdon commented 5 years ago

btw, we're continue our work on grapqhql server, maybe this will be also interesting for you as backend development. repo: https://github.com/GroceriStar/graphql-server