Skip to content

Conversation

@fabioquarantini
Copy link
Contributor

@fabioquarantini fabioquarantini commented May 28, 2025

Filtering and Control Options

Collection and Global Filtering

Control which collections and globals are included in the OpenAPI specification:

import { openapi } from 'payload-oapi'

// Basic filtering with arrays
buildConfig({
  plugins: [
    openapi({
      openapiVersion: '3.0',
      metadata: { title: 'Public API', version: '1.0.0' },
      
      // Include only specific collections
      includeCollections: ['posts', 'categories'],
      
      // Exclude sensitive globals
      excludeGlobals: ['internal-settings'],
      
      // Hide internal Payload collections (payload-preferences, payload-migrations)
      hideInternalCollections: true,
    }),
  ],
})

// Advanced filtering with functions
buildConfig({
  plugins: [
    openapi({
      openapiVersion: '3.0',
      metadata: { title: 'Public API', version: '1.0.0' },
      
      // Custom filtering with functions
      includeCollections: ({ slug, config }) => {
        return config.auth || config.access?.read === true
      },
      
      excludeGlobals: ({ slug, config }) => {
        return slug.startsWith('internal-')
      },
    }),
  ],
})

Operation-Level Filtering

Control which CRUD operations are included for collections:

import { openapi } from 'payload-oapi'

// Include only specific operations
buildConfig({
  plugins: [
    openapi({
      openapiVersion: '3.0',
      metadata: { title: 'Read-Only API', version: '1.0.0' },
      
      operations: {
        includeOperations: ['read', 'list'],
      },
    }),
  ],
})

// Exclude dangerous operations
buildConfig({
  plugins: [
    openapi({
      openapiVersion: '3.0',
      metadata: { title: 'Safe API', version: '1.0.0' },
      
      operations: {
        excludeOperations: ['delete'],
      },
    }),
  ],
})

// Custom operation filtering per collection
buildConfig({
  plugins: [
    openapi({
      openapiVersion: '3.0',
      metadata: { title: 'Custom API', version: '1.0.0' },
      
      operations: {
        operationFilter: (operation, collection) => {
          // Only allow read operations for sensitive collections
          if (collection.slug === 'users') {
            return ['read', 'list'].includes(operation)
          }
          // Allow all operations for other collections
          return true
        }
      },
    }),
  ],
})

Field-Level Filtering

Control which fields are exposed in the documentation:

import { openapi } from 'payload-oapi'

// Exclude specific fields by name
buildConfig({
  plugins: [
    openapi({
      openapiVersion: '3.0',
      metadata: { title: 'Clean API', version: '1.0.0' },
      
      excludeFields: ['internalNotes', 'adminComments'],
    }),
  ],
})

// Custom field filtering by type and name
buildConfig({
  plugins: [
    openapi({
      openapiVersion: '3.0',
      metadata: { title: 'Secure API', version: '1.0.0' },
      
      excludeFields: ({ name, type }) => {
        // Exclude all password-type fields and internal fields
        return type === 'password' || name.startsWith('_')
      },
    }),
  ],
})

// Advanced field filtering with collection context
buildConfig({
  plugins: [
    openapi({
      openapiVersion: '3.0',
      metadata: { title: 'Context-Aware API', version: '1.0.0' },
      
      excludeFields: ({ name, type, collection }) => {
        // Different filtering rules for different collections
        if (collection.slug === 'users') {
          // For users, exclude sensitive fields
          return ['password', 'salt', 'hash', 'resetPasswordToken'].includes(name)
        }
        
        if (collection.slug === 'posts') {
          // For posts, exclude internal fields and drafts
          return name.startsWith('_') || name === 'draft'
        }
        
        // For other collections, only exclude password fields
        return type === 'password'
      },
    }),
  ],
})

@janbuchar
Copy link
Owner

Hi @fabioquarantini and thanks for the contribution! Could you rebase this onto the current master branch to avoid conflicts?

@fabioquarantini fabioquarantini force-pushed the feature/collection-filtering branch from 32ffe7f to a6ffbc5 Compare May 28, 2025 14:41
@fabioquarantini
Copy link
Contributor Author

I've rebased the branch

@fabioquarantini
Copy link
Contributor Author

Is the pull request okay for you?

@janbuchar
Copy link
Owner

Hi @fabioquarantini, I still haven't found the time to look into it - sorry for that. The huge change in the test snapshot kinda threw me off balance 🙂 Perhaps if you could sum up the changes in that and why it needed to happen, it would speed up the review process for me.

@fabioquarantini
Copy link
Contributor Author

Explaining it here isn’t easy. If you need any clarification, feel free to ask.

Copy link
Owner

@janbuchar janbuchar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not gonna lie, it is really hard to read this as a whole. I highlighted some places where refactoring may help, let me know what you think.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some unexpected changes in schema names etc. which make this hard to review. Any chance you could undo these?

const mockCollections = {
posts: {
config: { slug: 'posts', auth: false },
} as unknown as Collection,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please write the config in a way that actually satisfies the Collection type instead of casting to unknown

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a lot of repetition that makes it hard to review this. Do you see any way to refactor this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants