👋 Next.js Conf 2024: Come build, party, run, and connect with us! See all events

Discussion about creating and rendering documents in Sanity Studio using the HTTP API and `S.documentList()`.

106 replies
Last updated: Apr 21, 2021
what does it mean?
Apr 20, 2021, 2:51 PM
my code

export default () =>
  S.list()
    .title('Content')
    .items([
      S.listItem()
        .title('Gestione Categorie')
        .child(async () => {
          const { data: categories } = await getCategories();
          return categories?.map((element) =>
            S.document()
              .title(carTypes[element])
              .documentId(`category-${element.toLowerCase()}`)
              .schemaType('categoriesSettings')
          );
        }),
      // Add a visual divider (optional)d
      S.divider(),
      // List out the rest of the document types, but filter out the config type
      ...S.documentTypeListItems().filter(
        (listItem) => !['categoriesSettings'].includes(listItem.getId())
      ),
    ]);
Apr 20, 2021, 2:52 PM
It looks like your
S.document()
doesn’t have a
.schemaType()
assigned.
Apr 20, 2021, 3:45 PM
but it’s wrong
Apr 20, 2021, 3:47 PM
user A
but it’s not true 😐
Apr 20, 2021, 3:52 PM
sa you can see in the code
Apr 20, 2021, 3:52 PM
Yes, I see. Just trying to get the same thing going in my code.
Apr 20, 2021, 3:53 PM
this is my code
Apr 20, 2021, 3:53 PM
import S from '@sanity/desk-tool/structure-builder';
import carTypes from './static/categories';
import axios from 'axios';
import { IGetCategoryResponse } from '../server/src/controllers/getCategoriesController';
const http = axios.create({
  baseURL: '<http://localhost:5000/api/v1>',
  timeout: 1000,
});

function getCategories(): Promise<IGetCategoryResponse> {
  return http.get('/cms/categories').then((res) => res.data);
}

export default () =>
  S.list()
    .title('Content')
    .items([
      S.listItem()
        .title('Gestione pagina dei risultati')
        .child(
          S.list()
            .title('Risultati per:')
            .items([
              S.listItem()
                .title('Categoria')
                .child(async () => {
                  const { data: categories } = await getCategories();
                  return categories?.map((element) =>
                    S.document()
                      .schemaType('categoriesSettings')
                      .title(carTypes[element])
                      .documentId(`category-${element}`)
                  );
                }),
            ])
        ),
      // Add a visual divider (optional)d
      S.divider(),
      // List out the rest of the document types, but filter out the config type
      ...S.documentTypeListItems().filter(
        (listItem) => !['categoriesSettings'].includes(listItem.getId())
      ),
    ]);
Apr 20, 2021, 3:53 PM
you can replace the categories with an array of strings
Apr 20, 2021, 3:54 PM
thanks for the help!
Apr 20, 2021, 3:54 PM
I will try in a couple of minutes, and I will let you know
Apr 21, 2021, 7:26 AM
This solution will render the document as listItem but I’m not able to edit the document.
Apr 21, 2021, 7:57 AM
morehover I’ve installed a plugin to order documents and I cant’ see that documents cause they are list item not a real documents
Apr 21, 2021, 7:58 AM
That's correct - you are pulling in these categories from outside the studio, so they are not actual documents until you create them. The above only sets them up in the desk structure so you can more easily create them with specific document IDs.
Regarding not being able to edit the documents, could you share your schema definitions for the
categoriesSettings
document type? Have you defined
__experimental_actions
by any chance?
Apr 21, 2021, 8:22 AM
That's correct - you are pulling in these categories from outside the studio, so they are not actual documents until you create them. The above only sets them up in the desk structure so you can more easily create them with specific document IDs.
Regarding not being able to edit the documents, could you share your schema definitions for the
categoriesSettings
document type? Have you defined
__experimental_actions
by any chance?
Apr 21, 2021, 8:22 AM
yep
Apr 21, 2021, 8:22 AM
__experimental_actions: [/*‘create’,*/ ‘update’, /*‘delete’,*/ ‘publish’],
Apr 21, 2021, 8:22 AM
is this the problem?
Apr 21, 2021, 8:22 AM
That's correct - you are pulling in these categories from outside the studio, so they are not actual documents until you create them. The above only sets them up in the desk structure so you can more easily create them with specific document IDs.
Regarding not being able to edit the documents, could you share your schema definitions for the
categoriesSettings
document type? Have you defined
__experimental_actions
by any chance?
Apr 21, 2021, 8:22 AM
Indeed, by commenting out "create" you are preventing the creation of these documents. What you could try if you do not want to allow additional
categoriesSettings
documents in the future, is temporarily uncommenting, then creating the docs by adding content to them, and commenting out
create
once more.
Apr 21, 2021, 8:24 AM
and If i will add more “categories” in the future on my api?
Apr 21, 2021, 8:24 AM
I have to remove the comment everytime?
Apr 21, 2021, 8:24 AM
why I can’t create directly the document instead of list item?
Apr 21, 2021, 8:26 AM
I read something about in the docs that was possibile
Apr 21, 2021, 8:26 AM
Then the same will apply, so you may want to consider taking a different route: either always allowing the creation of these documents or instead creating the documents using the HTTP API instead, which will ignore
__experimental_actions
(it's just a studio concept).
Apr 21, 2021, 8:26 AM
For more information on creating docs using the HTTP API, see also: https://www.sanity.io/docs/http-mutations#c732f27330a4
Apr 21, 2021, 8:27 AM
By putting a string in this method, it will create a document with that ID if it doesn't already exist. 
Apr 21, 2021, 8:30 AM
That's right: in the code above you are using this approach (
S.document
is in the
S.listItem
child) - when you start adding content to the empty documents, it will create a document with the provided ID. However, the creation process does rely on the
create
action being allowed for the document type.
Apr 21, 2021, 8:36 AM
That's right: in the code above you are using this approach (
S.document
is in the
S.listItem
child) - when you start adding content to the empty documents, it will create a document with the provided ID. However, the creation process does rely on the
create
action being allowed for the document type.
Apr 21, 2021, 8:36 AM
so the right approach is to create that documents
Apr 21, 2021, 8:38 AM
from the api
Apr 21, 2021, 8:38 AM
not in the studio
Apr 21, 2021, 8:39 AM
so if I have to render all the documents for that specific schemaType what I have to do?
Apr 21, 2021, 8:42 AM
If you want to disable document creation for a type in the studio and still create documents for it without temporarily adding
create
as an allowed action, then using the HTTP API is indeed a good alternative.
To render all documents available for a specific schema type, you can use a
documentList
instead. For example:
// deskStructure.js
...
S.listItem()
  .title('Categories')
  .child(
    S.documentList()
      .title('Categories')
      .filter('_type == "categoriesSettings"')
  ),
Apr 21, 2021, 8:45 AM
ok yes it work
Apr 21, 2021, 8:52 AM
ok yes it work
Apr 21, 2021, 8:52 AM
I have to facing the api now
Apr 21, 2021, 8:53 AM
Sorry about the confusion. There's plenty of stuff to get your head around at the beginning, but there are many advantages to being familiar with the HTTP API if you want to build advanced functionality later 🙂 Do let us know if you have any other questions.
Apr 21, 2021, 8:56 AM
Yeah i know,
Apr 21, 2021, 8:56 AM
I’m going to dig in to api docs
Apr 21, 2021, 8:56 AM
the token
Apr 21, 2021, 9:00 AM
the token
Apr 21, 2021, 9:00 AM
is going to expire?
Apr 21, 2021, 9:00 AM
I have to get it once?
Apr 21, 2021, 9:00 AM
If you use your user auth token (
sanity debug --secrets
), it will indeed expire. However, you can set up robot tokens by opening your project on manage.sanity.io and going to Settings &gt; API &gt; Tokens &gt; Add new token. These will not expire 🤖
Apr 21, 2021, 9:05 AM
ooooook
Apr 21, 2021, 9:06 AM
sorry one last question
Apr 21, 2021, 9:07 AM
<dataset-name>
Apr 21, 2021, 9:07 AM
is?
Apr 21, 2021, 9:07 AM
The name of your dataset (
production
by default). You can find all datasets on your project by going to your project on manage.sanity.io and opening the Datasets tab - or by using the
sanity dataset list
command in your CLI (make sure to run it from your studio's root folder).
Apr 21, 2021, 9:09 AM
The name of your dataset (
production
by default). You can find all datasets on your project by going to manage.sanity.io &gt; Settings &gt; Datasets or using the
sanity dataset list
command in your CLI (make sure to run it from your studio's root folder).
Apr 21, 2021, 9:09 AM
okok
Apr 21, 2021, 9:09 AM

export async function postNewCategories(categories: string[]): Promise<void> {
  try {
    await <http://http.post|http.post>('/data/mutate/production', {
      mutations: categories.map((category: string) => ({
        create: {
          _id: category,
          _type: 'categoriesSettings',
          title: 'category',
        },
      })),
    });
  } catch (err) {
    console.log(err);
    throw new Error(err.message);
  }
}
Apr 21, 2021, 9:10 AM
so this should work
Apr 21, 2021, 9:10 AM
where http is an instance of axios with token and base url
Apr 21, 2021, 9:10 AM
I will le you know 😄
Apr 21, 2021, 9:10 AM
Yep, that looks alright to me as long as you can guarantee
category
is unique enough for future usage as these document IDs have to be unique 🙂
Apr 21, 2021, 9:11 AM
yep those are unique cause I’ve already do a normalization my backend side
Apr 21, 2021, 9:19 AM
yep those are unique cause I’ve already do a normalization my backend side
Apr 21, 2021, 9:19 AM
it wokrs!!! ❤️
Apr 21, 2021, 9:21 AM
if it already exsist what happen?
Apr 21, 2021, 9:22 AM
Awesome! The operation will fail if a document with the provided ID already exists. If you prefer that it doesn't fail but skips existing ones, you can use
createIfNotExists
instead of
create
. If you wish to replace docs if they already exist, you can use
createOrReplace
(not recommended here).
Apr 21, 2021, 9:25 AM
ok ok maybe createIfNotExists is perfect
Apr 21, 2021, 9:25 AM
S.documentList()
      .title('Categories')
      .filter('_type == "categoriesSettings"')
Apr 21, 2021, 10:00 AM
In you experience is possibile to add a sort on this by specific field inside the document?
Apr 21, 2021, 10:00 AM
i mean, I’m using a plugin for ordering, and I would like to refect the ordering in the menu
Apr 21, 2021, 10:00 AM
when I use create from api I have to referecing the name of the schema right?
Apr 21, 2021, 10:39 AM
eg:
Apr 21, 2021, 10:39 AM
name: ‘resultBrandsSettings’, type: ‘document’,
title: ‘Brands’,
Apr 21, 2021, 10:39 AM
resultBrandsSettings
Apr 21, 2021, 10:39 AM
That's correct: the
_type
(mind the underscore) should be set to the schema type (
resultBrandsSettings
in this case)
Apr 21, 2021, 10:40 AM
That's correct: the
_type
(mind the underscore) should be set to the schema type (
resultBrandsSettings
in this case)
Apr 21, 2021, 10:40 AM
it’s weird cause I’ve set it up all correct
Apr 21, 2021, 10:40 AM
the api works but results arent’ shown
Apr 21, 2021, 10:40 AM
what can I do to debug?
Apr 21, 2021, 10:41 AM
i’m trying in vision mode to quering
Apr 21, 2021, 10:41 AM
*[_type=="resultBrandsSettings"]
Apr 21, 2021, 10:41 AM
Are you able to query the documents? e.g.
sanity documents query '*[_type == "resultBrandsSettings"]'
Apr 21, 2021, 10:41 AM
Using Vision is fine too here
Apr 21, 2021, 10:42 AM
the array is empty
Apr 21, 2021, 10:42 AM
the function works, and the array with results is passed to the function
export async function postNewBrands(brands: IBrand[]): Promise<void> {
  try {
    await <http://http.post|http.post>('/data/mutate/production', {
      mutations: brands.map((brand: IBrand) => ({
        createIfNotExists: {
          _id: brand.id,
          _type: 'resultBrandsSettings',
          title: brand.name,
        },
      })),
    });
  } catch (err) {
    throw new Error(
      `Sanity API Error: status:${err?.response?.status}, statusCode: ${err?.response?.statusText}`
    );
  }
}
Apr 21, 2021, 10:42 AM
uhm
Apr 21, 2021, 10:42 AM
same for categories
Apr 21, 2021, 10:42 AM
Looks like only those docs are in your dataset right now: https://e83iap8s.api.sanity.io/v1/data/query/production?query=*
Apr 21, 2021, 10:44 AM
yeah
Apr 21, 2021, 10:45 AM
why?
Apr 21, 2021, 10:45 AM
on the Backend side i’ve changed just the name of the schema
Apr 21, 2021, 10:45 AM
nothing else
Apr 21, 2021, 10:45 AM
the weird part is if i change the method to create
Apr 21, 2021, 10:47 AM
i got conflicts
Apr 21, 2021, 10:47 AM
Apr 21, 2021, 10:47 AM
categories [
  'cabrio-coupe',
  'city-car',
  'minivan',
  'other',
  'sedan',
  'suv',
  'van',
  'wagon'
]
Error: Sanity API Error: status:409, statusCode: Conflict
Apr 21, 2021, 10:48 AM
Have you double-checked your Axios instance uses the correct base URL (project ID and dataset name)?
Apr 21, 2021, 10:48 AM
That's correct though: those documents exist - just not under the document type. I'm suspecting it's an ID conflict as they share the same ID this way.
Apr 21, 2021, 10:49 AM
yes all correct in axios
Apr 21, 2021, 10:50 AM
oh ok
Apr 21, 2021, 10:50 AM
make sense
Apr 21, 2021, 10:50 AM
So i have to delete all before
Apr 21, 2021, 10:50 AM
Either that or adapt the IDs
Apr 21, 2021, 10:51 AM
let me delete
Apr 21, 2021, 10:51 AM
yep
Apr 21, 2021, 10:52 AM
fixed
Apr 21, 2021, 10:52 AM
yep
Apr 21, 2021, 10:52 AM
thanks buddy
Apr 21, 2021, 11:04 AM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?