rest – Expose the resource as your father's son or not?

Let's say each word belongs to a dictionary. What is the preferable URI for a single word, either / word /: word (with dictionary_id a required GET parameter) or / dictionary /: id / word /: word?

Whatever you want.

/word/1
/dictionary/2/word/1
/dictionary/2?word/1
/dictionary/2?word=1
/word/1/dictionary/2
/word/1?dictionary/2
/word/1?dictionary=2
/6b1fc184-7053-4c68-aa15-66ddb24d3f93

Those are all penalty fee; REST does not care what spelling it uses for its resource identifiers, or what information it encodes in them.

office365apis: how to get underlying data in the SharePoint list through the REST API?

This is in Angular8 a written service for such queries. You can see them here

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { map, switchMap, tap } from 'rxjs/operators';
import { environment } from '../environments/environment';

const SP_SITE = 'https://(tenant).sharepoint.com(/your_subsite)';
const CRLF = 'rn';
const MAX_RECORDS = 1000;
const PEOPLE_SOURCE_ID = 'B09A7990-05EA-4AF9-81EF-EDFAB16C4E31';
const DIGEST_INTERVAL = 6e5; // 10 minutes
const CONTEXT_INFO = `${SP_SITE}/_api/contextinfo`;
const BATCH_API = `${SP_SITE}/_api/$batch`;
const PEOPLE_MANAGER = `${SP_SITE}/_api/SP.UserProfiles.PeopleManager`;
const LIST_API = `${SP_SITE}/_api/Web/Lists`;
const LIST_ITEMS_API = (list: string) => `${LIST_API}/GetByTitle('${list}')/Items`;
const MY_PROFILE_API = `${PEOPLE_MANAGER}/GetMyProperties`;
const PROFILE_API = (account: string) => `${PEOPLE_MANAGER}/GetPropertiesFor(accountName=@v)?@v='${account}'`;
const USERS_API = (query: string) => `${SP_SITE}/_api/search/query?querytext=${query}&sourceId='${PEOPLE_SOURCE_ID}'`;
const PICTURE_URL = (user: string, size: string) => `${SP_SITE}/_layouts/15/userphoto.aspx?size=${size}&username=${user}`;
const USER_ID_API = (account: string) => `${SP_SITE}/_api/web/siteusers?$top=1&$select=Id&$filter=LoginName eq '${account}'`;
const WF_INSTANCE = (type: string) => `${SP_SITE}/_api/SP.WorkflowServices.Workflow${type}Service.Current`;
const WF_SUBSCRIPTIONS = `${WF_INSTANCE('Subscription')}/EnumerateSubscriptions()?$select=Name,Id`;
const WF_START = (query: string) => `${WF_INSTANCE('Instance')}/StartWorkflowOnListItemBySubscriptionId(${query})`;

export interface ISharepointListItem {
  __metadata: IMetadata;
  Id: number;
  Title?: string;
  AuthorId?: number;
}
export interface ISharepoint {
  d: ISharepointD;
}
export interface ISharepointItem {
  d: T;
}
export interface ISharepointFieldChoices {
  d: ISharepointD<{
    Choices: {
      results: string();
    };
  }()>;
}
export interface ISharepointUser {
  (key: string): any;
  AccountName: string;
  DisplayName: string;
  Email: string;
  UserProfileProperties: {
    results: ISharepointObject();
  };
}
export interface ISharepointUserId {
  d: {
    results: {
      Id: number;
    }();
  };
}
export interface ISharepointProfileProps {
  d: {
    UserProfileProperties: {
      results: ISharepointObject();
    };
  };
}
export interface ISharepointContextInfo {
  d: {
    GetContextWebInformation: {
      FormDigestValue: string;
    };
  };
}
export interface ISharepointSearch {
  d: {
    query: {
      PrimaryQueryResult: {
        RelevantResults: {
          Table: {
            Rows: {
              results: {
                Cells: { results: ISharepointObject(); };
              }();
            };
          };
        };
      };
    };
  };
}
interface ISharepointObject {
  Key: string;
  Value: string;
}
interface ISharepointD {
  results: T;
  __next?: string;
  ItemCount?: number;
}
interface IMetadata {
  etag: string;
}

/**
 *
 * SharepointService is the base class to Sharepoint
 */
export class SharepointService {

  private static RequestDigest: { value: string, timestamp: number } = null;
  private static ME: ISharepointUser = null;

  /** Max Records listdata.svc can fetch via REST */
  public maxRecords: number = MAX_RECORDS;

  /**
   * Constructor to init SharepointService
   */
  constructor(private httpClient: HttpClient) {
    // this.generateBatch('create', 'SampleList', ({Title: '2', Message: '2'})).subscribe(data => console.log(data));
  }

  /**
   * API Default headers merged with passed values
   *
   * @param (options) If headers are passed they are merged with defaults
   * @returns headers
   */
  private getHeaders(options?: object): { headers: HttpHeaders } {
    const defaults = {
      Accept: 'application/json;odata=verbose'
    };
    return { headers: new HttpHeaders(Object.assign(defaults, options || {})) };
  }

  /**
   * Context Info for Invasive operations
   *
   * @returns formDigestValue
   */
  private getContextFormDigest(): Observable {
    const digest = SharepointService.RequestDigest;
    if (digest != null && (new Date().getTime() - digest.timestamp) < DIGEST_INTERVAL) {
      return of(digest.value);
    } else {
      return this.httpClient.post(CONTEXT_INFO, {}, this.getHeaders())
        .pipe(
          map(res => res.d.GetContextWebInformation.FormDigestValue),
          tap(value => {
            SharepointService.RequestDigest = {
              value,
              timestamp: new Date().getTime()
            };
          })
        );
    }
  }

  /**
   * Count all the items in a list or based on query
   * NOTE: On passing a query it might not be right always but should work if < 100
   *
   * @param listName The name of the list
   * @returns countItems
   */
  protected count(listName: string, query?: string): Observable {
    const countUrl = query ? 'Items' : 'ItemCount';
    return this.httpClient.get>(
      `${LIST_API}/GetByTitle('${listName}')/${countUrl}?${query || ''}`,
      this.getHeaders()
    )
      .pipe(map(res => query ? res.d.results.length : res.d.ItemCount));
  }

  /**
   * Create Item with this call
   *
   * @param data The record that is to be created
   * @param listName the sharepoint list from where the record needs to be deleted
   * @returns newItem
   */
  protected create(listName: string, data: T): Observable> {
    return this.getContextFormDigest()
      .pipe(
        switchMap(requestDigest => this.httpClient.post>(
          LIST_ITEMS_API(listName),
          { ...data, __metadata: { type: `SP.Data.${listName}ListItem` } },
          this.getHeaders({
            'Content-Type': 'application/json;odata=verbose',
            'X-RequestDigest': requestDigest,
          })
        ))
      );
  }

  /**
   * Retrieve item by Id with this call
   *
   * @param listName the listname where the id is to be passed
   * @param id id of listItem
   * @returns item
   */
  protected retrieveById(listName: string, id: number): Observable> {
    return this.httpClient.get>(`${LIST_ITEMS_API(listName)}(${id})`, this.getHeaders());
  }

  /**
   * Retrieve item(s) with this call
   *
   * @param listName the listname where the query is to be passed
   * @param query the query string to pass to the REST api
   * @returns listOfItems
   */
  protected retrieve(listName: string, query?: string): Observable> {
    return this.httpClient.get>(`${LIST_ITEMS_API(listName)}?${query || ''}`, this.getHeaders());
  }

  /**
   * Update Item with this call
   *
   * @param listName the sharepoint list from where the record needs to be deleted
   * @param data The record that is to be deleted
   * @returns updatedItem
   */
  protected update(listName: string, data: T): Observable> {
    return this.getContextFormDigest()
      .pipe(
        switchMap(requestDigest => this.httpClient.post>(
          `${LIST_ITEMS_API(listName)}(${data.Id})`,
          { ...data, __metadata: { type: `SP.Data.${listName}ListItem` } },
          this.getHeaders({
            'Content-Type': 'application/json;odata=verbose',
            'X-RequestDigest': requestDigest,
            'X-HTTP-Method': 'MERGE',
            'If-Match': data.__metadata.etag
          })
        ))
      );
  }

  /**
   * Delete Item with this call
   *
   * @param listName the sharepoint list from where the record needs to be deleted
   * @param data The record that is to be deleted
   * @returns confirmation
   */
  protected delete(listName: string, data: T): Observable> {
    return this.getContextFormDigest()
      .pipe(
        switchMap(requestDigest => this.httpClient.post>(
          `${LIST_ITEMS_API(listName)}(${data.Id})`,
          null,
          this.getHeaders({
            'Content-Type': 'application/json;odata=verbose',
            'X-RequestDigest': requestDigest,
            'X-HTTP-Method': 'DELETE',
            'If-Match': data.__metadata.etag
          })
        ))
      );
  }

  /**
   * Gets all the choices of a choice field from List
   *
   * @param listName the name of the list
   * @param fieldName the choice field name
   * @returns choices string array
   */
  protected getFieldChoices(listName: string, fieldName: string): Observable {
    const url = `${LIST_API}/GetByTitle('${listName}')/fields?$filter=EntityPropertyName eq '${fieldName}'`;
    return this.httpClient.get(url, this.getHeaders())
      .pipe(map(response => response.d.results(0).Choices.results));
  }

  /**
   * Fetch the Logged in User Information
   *
   * @returns loggedInUser
   */
  public getLoggedInUser(): Observable {
    if (SharepointService.ME !== null) {
      return of(SharepointService.ME);
    } else {
      return this.httpClient.get(
        `${MY_PROFILE_API}?$select=AccountName,DisplayName,Email,UserProfileProperties`,
        this.getHeaders()
      )
        .pipe(
          map(response => {
            const props = response.d.UserProfileProperties.results
              .filter(row => row.Value !== '')
              .reduce((result, row) => ({ ...result, (row.Key): row.Value }), {});
            return { ...response.d, ...props } as ISharepointUser;
          }),
          tap(user => {
            SharepointService.ME = user;
          })
        );
    }
  }

  /**
   * Gets the user based on passed user's account name
   *
   * @param accountName the account-name for the user
   * @returns userDetails
   */
  protected getProfileData(accountName: string): Observable {
    const url = `${PROFILE_API(encodeURIComponent(accountName))}&$select=AccountName,DisplayName,Email,UserProfileProperties`;
    return this.httpClient.get(url, this.getHeaders())
      .pipe(
        map(response => {
          const props = response.d.UserProfileProperties.results
            .filter(row => row.Value !== '')
            .reduce((result, row) => ({ ...result, (row.Key): row.Value }), {});
          return { ...response.d, ...props } as ISharepointUser;
        })
      );
  }

  /**
   * Gets the sharepoint userId based on passed user's account name
   *
   * @param accountName the account-name for the user
   * @returns sharepointUserId
   */
  protected getUserId(accountName: string): Observable {
    return this.httpClient.get(USER_ID_API(encodeURIComponent(accountName)), this.getHeaders())
      .pipe(
        map(response => response.d.results(0).Id)
      );
  }

  /**
   * Gets the picture url for the profile
   *
   * @param email email id of the user
   * @returns url of the picture
   */
  protected getPictureUrl(email: string, size: string): string {
    return PICTURE_URL(email, size);
  }

  /**
   * Search all users based on the search input string
   *
   * @param term the search term to search
   * @returns users matched by search term
   */
  protected searchUsers(term: string): Observable {
    if (!term) {
      return of(());
    } else {
      const query = `'(${this.notNullSearchFilter('SipAddress')}) AND (PreferredName:*${term}* OR SipAddress:*${term}*)'`;
      const url = `${USERS_API(query)}&selectproperties='AccountName,SipAddress,Title,PreferredName,PictureURL'`;
      return this.httpClient.get(url, this.getHeaders())
        .pipe(map(response => (response.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results
          .map(row => row.Cells.results
            .reduce((result, rowItem) => ({ ...result, (rowItem.Key): rowItem.Value }), {} as ISharepointUser)
          ))
        ));
    }
  }

  /**
   * An alternative to match all which is equivalent to not null which searching
   * #Refer *searchUsers()*
   *
   * @param column name of column to include
   * @returns queryNotNull for a column
   */
  private notNullSearchFilter(column: string): string {
    // Fucked up logic for sharepoint not null
    return '_abcefghijklmonpqrstuvwxyz0123456789'
      .split('')
      .map(unit => `${column}:${unit}*`)
      .join(' OR ');
  }

  /**
   * Do Attachments Operations like delete, retrieve, and add to a list
   *
   * @param mode the nature of operation GetAttachments | DeleteAttachment | AddAttachment
   * @param id The Id of the List Item
   * @param listName The name of the list
   * @param (fileName) The Name of the file required for DeleteAttachment/AddAttachment operations
   * @param (fileData) The File data required when adding the file for AddAttachment operation
   * @returns attachmentList | confirmation | newItem
   */
  protected doAttachmentsOperation(
    mode: string,
    id: number,
    listName: string,
    fileName?: string,
    fileData?: ArrayBuffer
  ): Observable {
    switch (mode) {
      case 'GetAttachments':
        return this.httpClient.get(`${LIST_API}/GetByTitle('${listName}')/Items(${id})/AttachmentFiles`, this.getHeaders());
      case 'DeleteAttachment':
        return this.getContextFormDigest()
          .pipe(
            switchMap(requestDigest => this.httpClient.post(
              `${LIST_API}/GetByTitle('${listName}')/Items(${id})/AttachmentFiles/GetByFileName('${fileName}')`,
              null,
              this.getHeaders({
                'X-RequestDigest': requestDigest,
                'X-HTTP-Method': 'DELETE',
              })
            ))
          );
      case 'AddAttachment':
        return this.getContextFormDigest()
          .pipe(
            switchMap(requestDigest => this.httpClient.post(
              `${LIST_API}/GetByTitle('${listName}')/Items(${id})/AttachmentFiles/Add(FileName='${fileName}')`,
              fileData,
              this.getHeaders({
                'X-RequestDigest': requestDigest,
                'Content-Type': undefined,
                // Microsoft proved me again that it is so stupid that can make you think you are stupid :(
              }),
            ))
          );
    }
  }

  /**
   * Transforms payload to acceptable Workflow input
   *
   * @param data payload for Workflow
   * @returns transformed request
   */
  private wfDataTransform(data: object): object {
    const primitiveTypes = { string: 'Edm.String', boolean: 'Edm.Boolean', number: 'Edm.Int32' };
    return {
      payload: Object.keys(data)
        .map(Key => ({
          Key,
          Value: data(Key),
          ValueType: primitiveTypes((typeof data(Key)))
        }))
    };
  }

  /**
   * Initiates a Workflow 2013
   *
   * @param workflow Name of the workflow to start
   * @param itemId The item that the workflow will init with context
   * @param data the associated data params
   * @returns workflow response
   */
  protected startWorkflow(workflow: string, itemId: number, data: object): Observable {
    return this.getContextFormDigest()
      .pipe(
        switchMap(requestDigest => this.httpClient.post(
          `${WF_SUBSCRIPTIONS}`,
          null,
          this.getHeaders({
            'Content-Type': 'application/json;odata=verbose',
            'X-RequestDigest': requestDigest,
          })
        )
          .pipe(
            map(response => {
              const subscription = response.d.results.find(sub => sub.Name === workflow);
              if (subscription) {
                return subscription.Id;
              } else {
                throw new Error('No Subsctiption found');
              }
            }),
            switchMap(subscriptionId => this.httpClient.post(
              `${WF_START(`subscriptionId='${subscriptionId}',itemId='${itemId}'`)}`,
              this.wfDataTransform(data),
              this.getHeaders({
                'Content-Type': 'application/json;odata=verbose',
                'X-RequestDigest': requestDigest,
              })
            ))
          )
        ),
        map(wfResponse => wfResponse.d.StartWorkflowOnListItemBySubscriptionId),
      );
  }

  /**
   * Generates an unique identifier for batch operations
   *
   * @returns uuid
   */
  private generateUUID(): string {
    let dateTime = new Date().getTime();
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/(xy)/g, (item) => {
      // tslint:disable:no-bitwise
      const replacer = (dateTime + Math.random() * 16) % 16 | 0;
      dateTime = Math.floor(dateTime / 16);
      return (item === 'x' ? replacer : (replacer & 0x7 | 0x8)).toString(16);
      // tslint:enable:no-bitwise
    });
  }

  /**
   * Batch CRUD method
   * NOTE: not working Sharepoint syntax is confusing
   *
   * @param operation any of CRUD
   * @param listName the sharepoint list from where the record needs to be operated
   * @param data the data for the operation
   * @returns custom response
   */
  private generateBatch(operation, listName, data): Observable {
    const batchGuid = this.generateUUID();
    const changeSetId = this.generateUUID();
    const batchContents = ();
    const changeContents = ();
    let dataSet = '';

    data.forEach(item => {
      changeContents.push(`--changeset_${changeSetId}`);
      changeContents.push(`Content-Type: application/http`);
      changeContents.push(`Content-Transfer-Encoding: binary`);
      changeContents.push(``);
      changeContents.push(`POST ${LIST_ITEMS_API(listName)} HTTP/1.1`);
      changeContents.push(`Content-Type: application/json;odata=verbose`);
      changeContents.push(``);
      changeContents.push(JSON.stringify({ ...item, __metadata: { type: `SP.Data.${listName}ListItem` } }));
      changeContents.push(``);
    });
    changeContents.push(`--changeset_${changeSetId}--`);

    dataSet = changeContents.join(CRLF);

    batchContents.push(`--batch_${batchGuid}`);
    batchContents.push(`Content-Type: multipart/mixed; boundary=changeset_${changeSetId}`);
    batchContents.push(`Content-Length: ${dataSet.length}`);
    batchContents.push(`Content-Transfer-Encoding: binary`);
    batchContents.push(``);
    batchContents.push(dataSet);
    batchContents.push(``);

    batchContents.push(`--batch_${batchGuid}`);
    batchContents.push(`Content-Type: application/http`);
    batchContents.push(`Content-Transfer-Encoding: binary`);
    batchContents.push(``);
    batchContents.push(`GET ${LIST_ITEMS_API(listName)} HTTP/1.1`);
    batchContents.push(`Accept: application/json;odata=verbose`);
    batchContents.push(``);

    batchContents.push(`--batch_${batchGuid}--`);

    const batchBody = batchContents.join(CRLF);

    return this.getContextFormDigest()
      .pipe(
        switchMap(requestDigest => this.httpClient.post(
          BATCH_API,
          batchBody,
          this.getHeaders({
            'Content-Type': `multipart/mixed; boundary=batch_${batchGuid}`,
            'X-RequestDigest': requestDigest,
            Accept: '*/*'
          })
        ))
      );
  }

}


Here is a sample recovery call

getItems(options): Observable {
    let query = null;
    if (typeof options === 'string') {
      query = options;
    } else {
      const filterObjects = ();
      filterObjects.push(options.Author ? `Author/Name eq '${encodeURIComponent(options.Author)}'` : '');
      filterObjects.push(options.AssignedTo ? `AssignedTo/Name eq '${encodeURIComponent(options.AssignedTo)}'` : '');
      filterObjects.push(options.AssignedTo === null ? `AssignedTo/Name eq null` : '');
      filterObjects.push(options.status ? `Status eq '${options.status}'` : '');
      filterObjects.push(options.id ? `Id eq ${options.id}` : '');
      const filters = `$filter=${filterObjects.filter(f => !!f).join(' and ')}`;

      const size = `$top=${this.pageSize}`;
      const selects = `$select=Id,Title,Message,Category,Status,Author/Name,AssignedTo/Name&$expand=Author,AssignedTo`;
      const orderBy = options.orderBy ? `$orderby=${options.orderBy}` : `$orderby=Created desc`;

      query = `${selects}&${filters}&${size}&${orderBy}`;
    }
    return this.retrieve(DATA_LIST, query)
      .pipe(
        tap(response => {
          const { __next: next } = response.d;
          this.nextSuggestionsDeferred = next && next.substring(next.indexOf('?') + 1);
        }),
        map(response => response.d.results.map(item => new Suggestion(item))),
        // delay(1e5)
      );
  }

windows – Error interacting with REST API User does not have permission bigquery.datasets.create in project

I am trying to use the Simba Bigquery ODBC driver to extract some data in an external database. While the connection works fine and I can see the project tables, I cannot run my SQL. The query works well in the online cloud environment.
Anyone know why is the error about bigquery.datasets.create permission and how to fix it?

rest – blue image upload workflow

I am working on a new project. It is an application for smartphones made with react-native. In the application, you can create "cards" that have a title, a description and a photo, taken by the user's phone.

I will use a SQL Server database, hosted on Azure and I am currently working on the REST-API with ASP.NET core with Entityframwork Core. Basically, this is not a new workflow for me, but I have never done it with file upload and storage.

Now my question is, how can I and should I deal with file upload? The most obvious thing for me is to store the file on some type of cloud storage server and save the URL in the image in the database so that I can simply have an image tag in my mobile application with the URL as the property of origin.

Another way I found is to store the image as an array of bytes directly in the database. But I don't like this way of doing it, because then I have to transfer the whole image every time I want to show it.

Is there any common way to achieve this? I really want to use Azure alone because I just started using the 12-month free trial.

Thank you,
Roman

webforms – patch method sample code REST API

I am working on web services in drupal. I have created a sample module to obtain the method to expose the data through web services. I have not found any sample code for the patch method.
code to get the method:

namespace Drupaldemo_rest_apiPluginrestresource;

use DrupalrestPluginResourceBase;
use DrupalrestResourceResponse;

class DemoResource extends ResourceBase {

}
/**
 * Provides a Demo Resource
 *
 * @RestResource(
 *   id = "demo_resource",
 *   label = @Translation("Demo Resource"),
 *   uri_paths = {
 *     "canonical" = "/demo_rest_api/demo_resource"
 *   }
 * )
 */
class DemoResource extends ResourceBase {

}
/**
 * Provides a Demo Resource
 *
 * @RestResource(
 *   id = "demo_resource",
 *   label = @Translation("Demo Resource"),
 *   uri_paths = {
 *     "canonical" = "/demo_rest_api/demo_resource"
 *   }
 * )
 */
class DemoResource extends ResourceBase {

  /**
   * Responds to entity GET requests.
   * @return DrupalrestResourceResponse
   */
  public function get() {
    $response = ('message' => 'Hello, this is a rest service');
    return new ResourceResponse($response);
  }
}

I am new to drupal. I didn't find any examples for the patch method. Can anyone advertise or provide a sample code for the patch method?

PD: I didn't find any tags for web services.

Thanks in advance

Need help in the SharePoint Rest search API with POSTMAN

I am integrating Sharepoint with POSTMAN, first of all, I created an application and obtained the client identification and the client's secret key with which I generate the oAuth authentication and it is working perfectly well. Now when I try to search using http://tenant.sharepoint.com/_api/search/query?querytext=&#39;change & # 39; I get {"error_description": "Invalid issuer or signature".

I tried passing grant_type because client credentials remain the same error.

Postman

real analysis – $ L ^ p $ – form of the rest of the sequence limited by $ L ^ 2 $

We have a sequence of functions. $ (u_n) $ limited in $ L ^ 2 (M) $, where $ M $ it is a compact set in $ R ^ n $. We represent the sequence $ (u_n) $ at the orthonormal base $ {e_k } _ {k en N} $ of $ L ^ 2 (M) $:
$$
u_n (x) = sum limits_ {k = 1} ^ infty a ^ n_k e_k (x)
$$
It is true
$$
lim limits_ {s to infty} sup limits_ {n in N} | sum limits_ {k = s} ^ infty a ^ n_k e_k ( cdot) | L ^ p (M)} = 0, 1 leq p <2.
$$

SharePoint 2010 workflows: is it possible to call the rest API?

So here is my situation, I am working in a SharePoint 2013 environment, but only SHarePoint 2010 workflows are enabled. I see many questions and blogs that describe making rest API calls in workflows. However, when I try to do the same things, I don't see the same options. So I'm hopeful, maybe there is a 2010 way to avoid that.

Direct question:
Is it possible to make API rest calls in SharePoint 2010 workflows?
If so, show me your secret sauce.

Final objective: I want to configure reports that are extracted from several lists and send them by email to the Administration. I currently do this with a Powershell script that calls rest api, then sends the report via email. I want to automate this process. But I am a user, I do not have access to the servers and I cannot configure the timer jobs. So I am trying to find some other way to achieve the same to run monthly, without having to press the button or run it manually.

rest: API key vs. user authentication for B2B transactions in idle service

I have been asked to think about how to ensure a quiet service that (at least for now) will require authentication of third-party B2B applications.

I understand that API keys are basically a token that is generated once, but that is used for a group of users that belong to an organization.

I understand that there are flexibility / security problems with API keys because they are often shared, cannot easily expire and update and do not have a payload of roles as JWT can do.

Given the above, which authentication scheme is best for the problem in question?

WordPress json rest api showing only 10 categories

The rest of WordPress API for categories shows only 10 categories. How can I get the entire list of categories in the API?
Please give me a hand with this.

Thank you