Ocop Class
OcopJS - Thành phần chính của @ocopjs gồm class & CLI. 🇻🇳
Lưu ý sau khi phiên bản KeystoneJS 5 chuyển sang chế độ duy trì để ra mắt phiên bản mới hơn. Chúng tôi đã dựa trên mã nguồn cũ này để phát triển một phiên bản khác với một số tính năng theo hướng microservices.
yarn add @ocopjs/ocop
Install latest dependencies
pnpm i @ocopjs/access-control@latest @ocopjs/app-version@latest @ocopjs/common@latest @ocopjs/utils@latest
Usage
const { Ocop } = require("@ocopjs/ocop");
const ocop = new Ocop({
adapter,
appVersion,
cookie,
cookieSecret,
defaultAccess,
onConnect,
queryLimits,
sessionStore,
schemaNames,
});
appVersion
Configure the application version, which can be surfaced via HTTP headers or GraphQL.
The version
can be any string value you choose to use for your system. If
addVersionToHttpHeaders
is true
then all requests will have the header
X-Ocop-App-Version
set. The version can also be queried from the GraphQL API
as { appVersion }
. You can control whether this is exposed in your schema
using access
, which can be either a boolean, or an object with schemaName
keys and boolean values.
const ocop = new Ocop({
appVersion: {
version: "1.0.0",
addVersionToHttpHeaders: true,
access: true,
},
});
Why don't we just use access
to control the HTTP header?
We want to attach the HTTP header at the very top of the middleware stack, so if something gets rejected we can at least be sure of the system version that did the rejecting. This happens well before we have worked out which schema the person is trying to access, and therefore our access control isn’t ready to be used. Also, the access control that we set up is all about controlling access to the GraphQL API, and HTTP headers are a Different Thing, so even if it was technically possible to use the same mechanism, it really makes sense to decouple those two things.
cookie
Default: see Usage.
A description of the cookie properties is included in the express-session documentation.
secure
A secure cookie is only sent to the server with an encrypted request over the
HTTPS protocol. If secure
is set to true (as is the default with a
production build) for a OcopJS project running on a non-HTTPS server (such
as localhost), you will not be able to log in. In that case, be sure you set
secure
to false. This does not affect development builds since this value is
already false.
You can read more about secure cookies on the MDN web docs.
Usage
const ocop = new Ocop({
/* ...config */
cookie: {
secure: process.env.NODE_ENV === "production", // Default to true in production
maxAge: 1000 * 60 * 60 * 24 * 30, // 30 days
sameSite: false,
},
});
cookieSecret
The secret used to sign session ID cookies. In production mode
(process.env.NODE_ENV === 'production'
) this option is required. In
development mode, if undefined, a random cookieSecret
will be generated each
time Ocop starts (this will cause sessions to be reset between restarts).
defaultAccess
Default:
{
list: true,
field: true,
custom: true
}
Default list and field access. See the Access Control page for more details.
onConnect
Default: undefined
Callback function that executes once ocop.connect()
is complete. Takes no
arguments.
queryLimits
Configures global query limits.
These should be used together with list query limits.
const ocop = new Ocop({
queryLimits: {
maxTotalResults: 1000,
},
});
maxTotalResults
: limit of the total results of all relationship subqueries
Note that maxTotalResults
applies to the total results of all relationship
queries separately, even if some are nested inside others.
sessionStore
Sets the Express server's session middleware. This should be configured before deploying your app.
This example uses the
connect-mongo
middleware, but
you can use
any of the stores that work with express session
.
const expressSession = require("express-session");
const MongoStore = require("connect-mongo")(expressSession);
const ocop = new Ocop({
sessionStore: new MongoStore({ url: "mongodb://localhost/my-app" }),
});
schemaNames
Default: ['public']
Methods
Method | Description |
---|---|
connect | Manually connect to Adapter. |
createAuthStrategy | Creates a new authentication middleware instance. |
createList | Add a list to the Ocop schema. |
disconnect | Disconnect from the adapter. |
extendGraphQLSchema | Extend ocops generated schema with custom types, queries, and mutations. |
prepare | Manually prepare Ocop middlewares. |
createContext | Create a context object that can be used with executeGraphQL() . |
executeGraphQL | Execute a server-side GraphQL operation within the given context. |
connect()
Manually connect Ocop to the adapter. See Custom Server.
ocop.connect();
Note:
ocop.connect()
is only required for custom servers. Most example projects use theocop start
command to start a server and automatically connect.
createAuthStrategy(config)
Creates a new authentication middleware instance. See:
const authStrategy = ocop.createAuthStrategy({...});
createList(listKey, config)
Registers a new list with Ocop and returns a Ocop
list object.
ocop.createList('Posts', {...});
Config
Option | Type | Default | Description |
---|---|---|---|
listKey | String | null | The name of the list. This should be singular, E.g. 'User' not 'Users'. |
config | Object | {} | The list config. |
disconnect()
Disconnect the adapter.
extendGraphQLSchema(config)
Extends ocops generated schema with custom types, queries, and mutations.
ocop.extendGraphQLSchema({
types: [{ type: "type MyType { original: Int, double: Float }" }],
queries: [
{
schema: "double(x: Int): MyType",
resolver: (_, { x }) => ({ original: x, double: 2.0 * x }),
},
],
mutations: [
{
schema: "triple(x: Int): Int",
resolver: (_, { x }) => 3 * x,
},
],
});
Config
Option | Type | Description |
---|---|---|
types | array | A list of objects of the form { type, access } where the type string defines a GraphQL type. |
queries | array | A list of objects of the form { schema, resolver, access } . |
mutations | array | A list of objects of the form { schema, resolver, access } . |
- The
schema
for both queries and mutations should be a string defining the GraphQL schema element for the query/mutation, e.g.
{
schema: 'getBestPosts(author: ID!): [Post]',
}
- The
resolver
for both queries and mutations should be a resolver function with following signature:
{
resolver: (parent, args, context, info, extra) => {},
}
For more information about the first four arguments, please see the
Apollo docs.
The last argument extra
is an object that contains the following property:
Name | Description |
---|---|
access | Access control information about the current user. |
- The
access
argument fortypes
,queries
, andmutations
are all either boolean values which are used at schema generation time to include or exclude the item from the schema, or a function which must return boolean. - See the Access control API docs for more details.
prepare(config)
Manually prepare middlewares. Returns a promise representing the processed
middlewares. They are available as an array through the middlewares
property
of the returned object.
Usage
const { middlewares } = await ocop.prepare({
apps,
dev: process.env.NODE_ENV !== "production",
});
Config
Option | Type | default | Description |
---|---|---|---|
apps | Array | [] | An array of 'Apps' which are express middleware. |
cors | Object | { origin: true, credentials: true } | CORS options passed to the cors npm module |
dev | Boolean | false | Sets the dev flag in Ocop' express middleware. |
distDir | String | dist | The build directory for ocop. |
pinoOptions | Object | undefined | Logging options passed to the express-pino-logger npm module |
createContext({ schemaName, authentication, skipAccessControl })
Create a context
object that can be used with executeGraphQL()
.
Usage
const { gql } = require('apollo-server-express');
// Create a context which can execute GraphQL operations with no access control
const context = ocop.createContext().sudo()
// Execute a GraphQL operation with no access control
const { data, errors } = await ocop.executeGraphQL({ context, query: gql` ... `, variables: { ... }})
Config
Option | Type | default | Description |
---|---|---|---|
schemaName | String | public | The name of the GraphQL schema to execute against. |
authentication | Object | {} | { item: { id }, listAuthKey: "" } . Specifies the item to be used in access control checks. |
skipAccessControl | Boolean | false | Set to true to skip all access control checks. |
executeGraphQL({ context, query, variables })
Execute a server-side GraphQL query within the given context.
Usage
const { gql } = require('apollo-server-express');
// Create a context which can execute GraphQL operations with no access control
const context = ocop.createContext().sudo()
// Execute a GraphQL operation with no access control
const { data, errors } = await ocop.executeGraphQL({ context, query: gql` ... `, variables: { ... }})
Config
Option | Type | default | Description |
---|---|---|---|
context | Array | ocop.createContext() | A context object to be used by the GraphQL resolvers. |
query | Object | undefined | The GraphQL operation to execute. |
variables | Object | undefined | The variables to be passed to the GraphQL operation. |