Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guild docs integration #3085

Merged
merged 1 commit into from
Jul 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,5 @@ junit.xml

package-lock.json
website/yarn.lock
website/api-sidebar.json
website/docs/api
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
},
"resolutions": {
"graphql": "15.5.1",
"esbuild": "^0.12.8",
"@changesets/apply-release-plan": "5.0.0"
}
}
48 changes: 31 additions & 17 deletions scripts/build-api-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ async function buildApiDocs() {
const packageJsonContent = require(path.join(__dirname, '..', packageJsonPath));
// Do not include private and large npm package that contains rest
if (
!packageJsonPath.includes('./website/') &&
!packageJsonContent.private &&
packageJsonContent.name !== MONOREPO &&
!packageJsonContent.name.endsWith('/container')
Expand Down Expand Up @@ -80,6 +81,13 @@ async function buildApiDocs() {
// Escape angle brackets
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
// Fix title
.replace(/^# .+/g, function (match) {
return `---
title: '${match.replace('# ', '')}'
---
${match}`;
})
// Fix links
.replace(/\[([^\]]+)\]\(([^)]+).md\)/g, '[$1]($2)')
.replace(/\[([^\]]+)\]\((\.\.\/(classes|interfaces|enums)\/([^\)]+))\)/g, '[$1](/docs/api/$3/$4)');
Expand Down Expand Up @@ -109,8 +117,8 @@ async function buildApiDocs() {
})
);

// Remove the generated "index.md" file
// fs.unlinkSync(path.join(outputDir, 'index.md'));
// Remove the generated "README.md" file
fs.unlinkSync(path.join(outputDir, 'README.md'));

// Update each module 's frontmatter and title
await Promise.all(
Expand Down Expand Up @@ -142,20 +150,27 @@ sidebar_label: "${id}"
fs.writeFileSync(
sidebarsPath,
JSON.stringify(
[
{
Modules: modules.map(([name]) => `api/modules/${convertNameToId(name)}`),
},
{
Classes: getSidebarItemsByDirectory(path.join(outputDir, 'classes')),
},
{
Interfaces: getSidebarItemsByDirectory(path.join(outputDir, 'interfaces')),
},
{
Enums: getSidebarItemsByDirectory(path.join(outputDir, 'enums')),
{
$name: 'API Reference',
_: {
modules: {
$name: 'Modules',
$routes: getSidebarItemsByDirectory(path.join(outputDir, 'modules')),
},
classes: {
$name: 'Classes',
$routes: getSidebarItemsByDirectory(path.join(outputDir, 'classes')),
},
interfaces: {
$name: 'Interfaces',
$routes: getSidebarItemsByDirectory(path.join(outputDir, 'interfaces')),
},
enums: {
$name: 'Enums',
$routes: getSidebarItemsByDirectory(path.join(outputDir, 'enums')),
},
},
],
},
null,
2
)
Expand Down Expand Up @@ -183,8 +198,7 @@ sidebar_label: "${id}"
const absoluteFilePath = path.join(dirName, fileName);
const fileLstat = fs.lstatSync(absoluteFilePath);
if (fileLstat.isFile()) {
const relativeDirName = path.relative(outputDir, dirName);
return `api/${relativeDirName}/${path.parse(fileName).name}`;
return path.parse(fileName).name;
} else {
return getSidebarItemsByDirectory(absoluteFilePath);
}
Expand Down
26 changes: 0 additions & 26 deletions website/.gitignore

This file was deleted.

42 changes: 0 additions & 42 deletions website/README.md

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,11 @@ This example has the entire type definition in one string and all resolvers in o

## Extending Types

It's easy to add additional fields to existing types using the `extend` keyword. Using `extend` is particularly useful in avoiding a large list of fields on root Queries and Mutations. You can use it like this:
It's easy to add additional fields to existing types using the `extend` keyword. Using `extend` is particularly useful in avoiding a large list of fields on root Queries and Mutations. You can use it like this:

```js
const typeDefs = [`
const typeDefs = [
`
schema {
query: Query
}
Expand All @@ -120,15 +121,17 @@ const typeDefs = [`
type Bar {
id
}
`, `
`,
`
type Foo {
id: String!
}

extend type Query {
foos: [Foo]!
}
`]
`,
];
```

If one of the types extended needs a resolver you can use `makeExecutableSchema` like this:
Expand All @@ -138,39 +141,42 @@ const barsResolver = {
Query: {
bars(parent, args, context, info) {
// ...
}
}
},
},
};

const foosResolver = {
Query: {
foos(parent, args, context, info) {
// ...
}
}
}
},
},
};

const schema = makeExecutableSchema({
typeDefs,
resolvers: [barsResolver, foosResolver]
})
resolvers: [barsResolver, foosResolver],
});
```

## Learning the GraphQL schema language

The official documentation on graphql.org now has [a section about GraphQL schemas](http://graphql.org/learn/schema/) which explains all of the different schema features and how to use them with the schema language.

The type definitions must define a query type, which means a minimal schema would look something like this:

```js
const typeDefs = [`
const typeDefs = [
`
schema {
query: RootQuery
}

type RootQuery {
aNumber: Int
}
`];
`,
];
```

## Descriptions & Deprecations
Expand Down Expand Up @@ -232,16 +238,16 @@ const jsSchema = makeExecutableSchema({
- `parseOptions` is an optional argument which allows customization of parse when specifying `typeDefs` as a string.

- `resolverValidationOptions` is an optional argument with the following properties, each of which can be set to `error`, `warn`, or `ignore`:

- `requireResolversForArgs` will cause `makeExecutableSchema` to throw an error (`error`) or issue a warning (`warn`)unless a resolver is defined for every field with arguments. The default is `ignore`, causing this validator to be skipped.

- `requireResolversForNonScalar` require a resolver for every non-scalar field. Default is `ignore`.

- `requireResolversForAllFields` asserts that *all* fields have valid resolvers. This option cannot be set in combination with the previous two validators. Default is `ignore`.
- `requireResolversForAllFields` asserts that _all_ fields have valid resolvers. This option cannot be set in combination with the previous two validators. Default is `ignore`.

- `requireResolversForResolveType` will require a `resolveType()` method for Interface and Union types. This can be passed in with the field resolvers as `__resolveType()`. Default is `ignore`.

- `requireResolversToMatchSchema` requires every resolver within the resolver map to correspond to a GraphQL entity within the schema. Defaults to `error`, to help catch common errors.

- `inheritResolversFromInterfaces` GraphQL Objects that implement interfaces will inherit missing resolvers from their interface types defined in the `resolvers` object.


File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,27 @@ The following is an example of a simple logged-in authorization logic:
Instead of doing this,

```js
const resolvers ={
Query: {
myQuery: (root, args, context) => {
// Make sure that the user is authenticated
if (!context.currentUser) {
throw new Error('You are not authenticated!');
}

// Make sure that the user has the correct roles
if (!context.currentUser.roles || context.currentUser.roles.includes('EDITOR')) {
throw new Error('You are not authorized!');
}

// Business logic
if (args.something === '1') {
return true;
}

return false;
},
const resolvers = {
Query: {
myQuery: (root, args, context) => {
// Make sure that the user is authenticated
if (!context.currentUser) {
throw new Error('You are not authenticated!');
}

// Make sure that the user has the correct roles
if (!context.currentUser.roles || context.currentUser.roles.includes('EDITOR')) {
throw new Error('You are not authorized!');
}

// Business logic
if (args.something === '1') {
return true;
}

return false;
},
},
};
```

Expand All @@ -42,36 +42,36 @@ You can do;
```js
const { composeResolvers } = require('@graphql-tools/resolvers-composition');

const resolvers ={
Query: {
myQuery: (root, args, context) => {
if (args.something === '1') {
return true;
}
const resolvers = {
Query: {
myQuery: (root, args, context) => {
if (args.something === '1') {
return true;
}

return false;
},
return false;
},
},
};

const isAuthenticated = () => next => async (root, args, context, info) => {
if (!context.currentUser) {
throw new Error('You are not authenticated!');
}
if (!context.currentUser) {
throw new Error('You are not authenticated!');
}

return next(root, args, context, info);
return next(root, args, context, info);
};

const hasRole = (role: string) => next => async (root, args, context, info) => {
if (!context.currentUser.roles || context.currentUser.roles.includes(role)) {
throw new Error('You are not authorized!');
}
if (!context.currentUser.roles || context.currentUser.roles.includes(role)) {
throw new Error('You are not authorized!');
}

return next(root, args, context, info);
return next(root, args, context, info);
};

const resolversComposition = {
'Query.myQuery': [isAuthenticated(), hasRole('EDITOR')],
'Query.myQuery': [isAuthenticated(), hasRole('EDITOR')],
};

const composedResolvers = composeResolvers(resolvers, resolversComposition);
Expand All @@ -80,12 +80,12 @@ const composedResolvers = composeResolvers(resolvers, resolversComposition);
`composeResolvers` is a method in `@graphql-tools/resolvers-composition` package that accepts `IResolvers` object and mappings for composition functions that would be run before resolver itself.

### Supported path matcher format

The paths for resolvers support `*` wildcard for types and glob patters for fields, eg:

- `*.*` - all types and all fields
- `Query.*` - all queries
- `Query.single` - only a single query
- `Query.{first, second}` - queries for first/second
- `Query.!first` - all queries but first
- `Query.!{first, second}` - all queries but first/second


File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ The resolver function for the `repositories` field of the `User` type would be r

```graphql
# To the subschema
query($id: ID!) {
query ($id: ID!) {
repositoriesByUserId(id: $id) {
id
url
Expand Down
File renamed without changes.
File renamed without changes.
Loading