Skip to content
Permalink
Browse files

release: 0.17.2

  • Loading branch information...
19majkel94 committed Apr 23, 2019
1 parent c965914 commit 1312584998b005b30a51b7ee528e0ad4bb6e6b72
@@ -1,12 +1,13 @@
# Changelog and release notes

## Unreleased
<!-- ## Unreleased -->
<!-- here goes all the unreleased changes descriptions -->
## v0.17.2
### Features
- add support for defining `resolveType` function for interfaces and unions (#319)
- add postinstall script for printing info on console about supporting the project
- add support for setting default nullability for fields and return types (#297)
- add `skipCheck` option in `buildSchema` to disable checking the correctness of a schema
- add postinstall script for printing info on console about supporting the project
### Fixes
- fix generating plain resolvers for queries and mutations (compatibility with Apollo client state)

Some generated files are not rendered by default. Learn more.

@@ -1,6 +1,6 @@
{
"name": "type-graphql",
"version": "0.17.1",
"version": "0.17.2",
"author": {
"name": "Michał Lytek",
"url": "https://github.com/19majkel94"
@@ -274,6 +274,26 @@
"version-0.17.1-validation": {
"title": "Argument and Input validation",
"sidebar_label": "Validation"
},
"version-0.17.2-examples": {
"title": "Examples",
"sidebar_label": "List of examples"
},
"version-0.17.2-getting-started": {
"title": "Getting started"
},
"version-0.17.2-interfaces": {
"title": "Interfaces"
},
"version-0.17.2-introduction": {
"title": "Introduction",
"sidebar_label": "What & Why"
},
"version-0.17.2-types-and-fields": {
"title": "Types and Fields"
},
"version-0.17.2-unions": {
"title": "Unions"
}
},
"links": {
@@ -0,0 +1,44 @@
---
title: Examples
sidebar_label: List of examples
id: version-0.17.2-examples
original_id: examples
---

On the [GitHub repository](https://github.com/19majkel94/type-graphql) there are a few simple examples of how to use different TypeGraphQL features and how well they integrate with 3rd party libraries.

All examples have an `examples.gql` file with sample queries/mutations/subscriptions that we can execute.

## Basics

- [Simple usage of fields, basic types and resolvers](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/simple-usage)

## Advanced

- [Enums and unions](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/enums-and-unions)
- [Subscriptions (simple)](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/simple-subscriptions)
- [Subscriptions (using Redis)](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/redis-subscriptions)
- [Interfaces](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/interfaces-inheritance)

## Features usage

- [Dependency injection (IoC container)](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/using-container)
- [scoped container](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/using-scoped-container)
- [Authorization](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/authorization)
- [Validation](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/automatic-validation)
- [Types inheritance](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/interfaces-inheritance)
- [Resolvers inheritance](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/resolvers-inheritance)
- [Generic types](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/generic-types)
- [Middlewares](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/middlewares)

## 3rd party libs integration

- [TypeORM (manual, synchronous) \*](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/typeorm-basic-usage)
- [TypeORM (automatic, lazy relations) \*](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/typeorm-lazy-relations)
- [Typegoose](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/typegoose)
- [Apollo Engine (Apollo Cache Control) \*\*](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/apollo-engine)
- [Apollo client state](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/apollo-client)

_\* Note that we need to edit the TypeORM example's `index.ts` with the credentials of our local database_

_\*\* Note that we need to provide an `APOLLO_ENGINE_API_KEY` env variable with our own API key_
@@ -0,0 +1,190 @@
---
title: Getting started
id: version-0.17.2-getting-started
original_id: getting-started
---

> Make sure you've completed all the steps described in the [installation instructions](installation.md).
To explore all of the powerful capabilities of TypeGraphQL, we will create a sample GraphQL API for cooking recipes.

Let's start with the `Recipe` type, which is the foundation of our API.

## Types

Our goal is to get the equivalent of this type described in SDL:

```graphql
type Recipe {
id: ID!
title: String!
description: String
creationDate: Date!
ingredients: [String!]!
}
```

So we create the `Recipe` class with all its properties and types:

```typescript
class Recipe {
id: string;
title: string;
description?: string;
creationDate: Date;
ingredients: string[];
}
```

Then we decorate the class and its properties with decorators:

```typescript
@ObjectType()
class Recipe {
@Field(type => ID)
id: string;
@Field()
title: string;
@Field({ nullable: true })
description?: string;
@Field()
creationDate: Date;
@Field(type => [String])
ingredients: string[];
}
```

The detailed rules of when to use `nullable`, `array` and others are described in the [fields and types docs](types-and-fields.md).

## Resolvers

After that we want to create typical crud queries and mutations. To do so, we create the resolver (controller) class that will have injected the `RecipeService` in the constructor:

```typescript
@Resolver(Recipe)
class RecipeResolver {
constructor(private recipeService: RecipeService) {}
@Query(returns => Recipe)
async recipe(@Arg("id") id: string) {
const recipe = await this.recipeService.findById(id);
if (recipe === undefined) {
throw new RecipeNotFoundError(id);
}
return recipe;
}
@Query(returns => [Recipe])
recipes(@Args() { skip, take }: RecipesArgs) {
return this.recipeService.findAll({ skip, take });
}
@Mutation(returns => Recipe)
@Authorized()
addRecipe(
@Arg("newRecipeData") newRecipeData: NewRecipeInput,
@Ctx("user") user: User,
): Promise<Recipe> {
return this.recipeService.addNew({ data: newRecipeData, user });
}
@Mutation(returns => Boolean)
@Authorized(Roles.Admin)
async removeRecipe(@Arg("id") id: string) {
try {
await this.recipeService.removeById(id);
return true;
} catch {
return false;
}
}
}
```

We use the `@Authorized()` decorator to restrict access to authorized users only or the users that fulfil the roles requirements.
The detailed rules for when and why we declare `returns => Recipe` functions and others are described in [resolvers docs](resolvers.md).

## Inputs and Arguments

Ok, but what are `NewRecipeInput` and `RecipesArgs`? They are of course classes:

```typescript
@InputType()
class NewRecipeDataInput {
@Field()
@MaxLength(30)
title: string;
@Field({ nullable: true })
@Length(30, 255)
description?: string;
@Field(type => [String])
@MaxArraySize(30)
ingredients: string[];
}
@ArgsType()
class RecipesArgs {
@Field(type => Int)
@Min(0)
skip: number = 0;
@Field(type => Int)
@Min(1)
@Max(50)
take: number = 25;
}
```

`@Length`, `@Min` and `@MaxArraySize` are decorators from [`class-validator`](https://github.com/typestack/class-validator) that automatically perform field validation in TypeGraphQL.

## Building schema

The last step that needs to be done is to actually build the schema from the TypeGraphQL definition. We use the `buildSchema` function for this:

```typescript
const schema = await buildSchema({
resolvers: [RecipeResolver],
});
// ...creating express server or sth
```

Et voilà! Now we have fully functional GraphQL schema!
If we print it, this is how it would look:

```graphql
type Recipe {
id: ID!
title: String!
description: String
creationDate: Date!
ingredients: [String!]!
}
input NewRecipeInput {
title: String!
description: String
ingredients: [String!]!
}
type Query {
recipe(id: ID!): Recipe
recipes(skip: Int = 0, take: Int = 25): [Recipe!]!
}
type Mutation {
addRecipe(newRecipeData: NewRecipeInput!): Recipe!
removeRecipe(id: ID!): Boolean!
}
```

## Want more?

That was only the tip of the iceberg - a very simple example with basic GraphQL types. Do you use interfaces, enums, unions and custom scalars? That's great because TypeGraphQL fully supports them too! There are also more advanced concepts like the authorization checker, inheritance support and field resolvers.

A lot of these topics are covered in Ben Awad's [Ben Awad](https://github.com/benawad)'s [TypeGraphQL video series](https://www.youtube.com/playlist?list=PLN3n1USn4xlma1bBu3Tloe4NyYn9Ko8Gs) on YouTube.

For more complicated cases, go to the [Examples section](examples.md) where you can discover e.g. how well TypeGraphQL integrates with TypeORM.
@@ -0,0 +1,74 @@
---
title: Interfaces
id: version-0.17.2-interfaces
original_id: interfaces
---

The main idea of TypeGraphQL is to create GraphQL types based on TypeScript classes.

In object-oriented programming it is common to create interfaces which describe the contract that classes implementing them must adhere to. Hence, TypeGraphQL supports defining GraphQL interfaces.

Read more about the GraphQL Interface Type in the [official GraphQL docs](https://graphql.org/learn/schema/#interfaces).

## Usage

TypeScript has first class support for interfaces. Unfortunately, they only exist at compile-time, so we can't use them to build GraphQL schema at runtime by using decorators.

Luckily, we can use an abstract class for this purpose. It behaves almost like an interface - it can't be "newed" but it can be implemented by the class - and it just won't prevent developers from implementing a method or initializing a field. So, as long as we treat it like an interface, we can safely use it.

How do we create a GraphQL interface definition? We create an abstract class and decorate it with the `@InterfaceType()` decorator. The rest is exactly the same as with object types: we use the `@Field` decorator to declare the shape of the type:

```typescript
@InterfaceType()
abstract class IPerson {
@Field(type => ID)
id: string;
@Field()
name: string;
@Field(type => Int)
age: number;
}
```

We can then we use this "interface" in the object type class definition:

```typescript
@ObjectType({ implements: IPerson })
class Person implements IPerson {
id: string;
name: string;
age: number;
}
```

The only difference is that we have to let TypeGraphQL know that this `ObjectType` is implementing the `InterfaceType`. We do this by passing the param `({ implements: IPerson })` to the decorator. If we implement multiple interfaces, we pass an array of interfaces like so: `({ implements: [IPerson, IAnimal, IMachine] })`.

We can also omit the decorators since the GraphQL types will be copied from the interface definition - this way we won't have to maintain two definitions and solely rely on TypeScript type checking for correct interface implementation.

## Resolving Type

Be aware that when our object type is implementing a GraphQL interface type, **we have to return an instance of the type class** in our resolvers. Otherwise, `graphql-js` will not be able to detect the underlying GraphQL type correctly.

We can also provide our own `resolveType` function implementation to the `@InterfaceType` options. This way we can return plain objects in resolvers and then determine the returned object type by checking the shape of the data object, the same ways [like in unions](./unions.md), e.g.:

```typescript
@InterfaceType({
resolveType: value => {
if ("grades" in value) {
return "Student"; // schema name of the type as a string
}
return Person; // or the object type class
},
})
abstract class IPerson {
// ...
}
```

However in case of interfaces, it might be a little bit more tricky than with unions, as we might not remember all the object types that implements this particular interface.

## Examples

For more advanced usage examples of interfaces (and type inheritance), e.g. with query returning an interface type, go to [this examples folder](https://github.com/19majkel94/type-graphql/tree/v0.17.2/examples/interfaces-inheritance).

0 comments on commit 1312584

Please sign in to comment.
You can’t perform that action at this time.