graphQL 2
@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 Schema
first, 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.
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/]
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
"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
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.
https://graphql.org/learn/queries/)
Chapter 2: Queries and Mutation (- 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. - Arguments: We can also pass arguments in the query for a field, to declaratively fetch data that is required.
- Aliases: Used for querying the same field with different arguments. Quite clear with the example there.
- Fragments: Cool feature, for modularising the query. Construct a set of fields, and then you can pass them into your query by
...fragmentName
. - Operation types: Any action is an operation. Operation can be of types query, mutation and subscription. Operations have types and name.
- Variables: variables can be also defined, for passing dynamic arguments in an operation. Variables can also be assigned default values.
- Directives: Used for dynamically manipulating the structure of the query. Like you can include or exclude some field by adding conditional statement on variables.
- 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. - 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.
- 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.
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
https://graphql.org/learn/schema/)
Chapter 3: Schemas and Types (- Type System: GraphQL has a strongly typed system, and we explicitly define types on each
field
of theobject
in the schema definition. Types can be defined as inObject types
using thetype
keyword, or they can be built-inscalar types
. By this, we can have an idea of what to expect when aquery
is made. Types are also needed for validation of the query. - Type Language: GraphQL has a uniques
SDL(Schema Description Language)
for describingschema
of the GraphQL service. - Object types and fields: An object type can have
fields
inside it, where each field can have ascalar type
as it's type or anotherobject type
as it's type. Basically this is the way of implementing relational databases. - Arguments: Every GraphQL field can have
multiple
arguments``, but they need to be explicitly passed by name. If an argument is optional we can assign a default value to it. - 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 amutation type
. Defined usingtype
keyword. Question: Can I only query data of fields for which I have a query type? - 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, usingscalar
keyword by doingscalar typeName
- 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'. - Lists and Non-Null: While defining the type on a field, we can also apply
type modifiers
to extend our type. We can doString!
to make the string typenon-nullable
. Once!
is added to the type, the server always expects a non-null value from that field. Second type modifier isList
, 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 doNumbers : [Int!]
to indicate the Numbers field is a list ofInt
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. - 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
. - 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 typeBreakfast
can be either of the typesSandwiches, Omelet or Oats
. When querying union types, we should always usein-line fragments
for each type(Sandwiches, Omelet, Oats) so that there is no error. - 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 formutations
, where we pass these input types to the object, we can even pass them asvariables
. Pretty cool! :)
https://graphql.org/learn/validation/)
Chapter 4: 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:
- A
fragment
cannot refer to itself: As this would create a cycle, sort ofrecurrence
but 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.
When querying
fields
, only query forfields
that are present in thattype
: Self explanatory, if we search for a field that is not present in the type, then it will be an error.If the query returns something other than a
scalar
orenum
, like an object type, then we need to specify whichfields
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?If a field is
scalar
, we cannot query any fields inside it.If our type
implements
aninterface
, then we can directly query only the fields on theinterface
. For querying type-specific fields, we can either useinline fragments
or create afragment
on the type.
https://graphql.org/learn/execution/)
Chapter 5: 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 scalar
type, 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:
obj
: The previous object, which we have to enter in order to resolve the query. This is not need for root resolver function.args
: The argument provided, for e.g.id
, orname
.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.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.