4. Mutation

4.1 A CRUD scenario

Once you have a Pokemon object, either retrieved via one, list or page, or simply instantiated. You can save that Pokemon by adding a save method.

function saveNewPokemon(pokemon: Pokemon) {
  return post<Pokemon>(POKEMON_API_URL, pokemon);
}

const bulbasaur = await saveNewPokemon({
  name: 'Bulbasaur',
  type: 'Grass'
});

It will then create a new Pokemon by performing a POST request.

To update an existing resource via a PUT request, you could add an update method:

function updatePokemon(pokemon: Pokemon) {
  return put<Pokemon>(`${POKEMON_API_URL}/${pokemon.id}`, pokemon);
}

/* 
  First fetch a pokemon using `one`.
*/
const bulbasaur = await onePokemon(42);

/*
  Update the pokemon
 */
await updatePokemon({ ...bulbasaur, xp: 5000 });

4.2 Uploading

When uploading files it is important to know that post, put and patch support FormData as the payload argument.

Often it is easiest when uploading to simply create a save method which can take a form to upload.

Here is an example of a form, it contains sprites which are either Files or urls as a string:

export type PokemonFormData = {
  id?: number;
  name: string;
  spriteFront: string | File;
  spriteBack: string | File;
}

Heres a save method that creates a multipart/form-data; request.

import { post, put } from '@42.nl/spring-connect';

const POKEMON_API_URL = '/api/pokemon';

export type Pokemon = {
  id: number;
  name: string;
  spriteFront: string;
  spriteBack: string;
};

/* This save either POST's a new pokemon, or PUTS to an existing one. */
function savePokemon(pokemonForm: PokemonFormData): Promise<Pokemon> {
  /* The formData will contain the pokemon and optionally the two sprites. */
  const formData = new FormData();

  /* If there is a front sprite File add it to the formData. */
  if (pokemonForm.spriteFront instanceof File) {
    formData.append('front', new Blob([pokemonForm.spriteFront]));
  }

  /* If there is a back sprite File add it to the formData. */
  if (pokemonForm.spriteBack instanceof File) {
    formData.append('back', new Blob([pokemonForm.spriteBack]));
  }

  /* Now remove the sprites */
  delete pokemonForm.spriteFront;
  delete pokemonForm.spriteBack;

  /* Append the pokemon blob. */
  const pokemon = new Blob([JSON.stringify(pokemonForm)], {
    type: 'application/json',
  });
  formData.append('pokemon', pokemon);

  /* POST on create, PUT on edit. */
  if (pokemonForm.id) {
    return put<Pokemon>(`${POKEMON_API_URL}/${pokemonForm.id}`, formData);
  } else {
    return post<Pokemon>(POKEMON_API_URL, formData);
  }
}