Mostre o que o servidor realmente aceitou

JavaScriptBeginner
Pratique Agora

Introdução

Os rótulos, a observação condicional e o layout responsivo da Still & Spoke estão prontos. O manipulador atual pode mostrar confirmação de demonstração sem enviar inscrição. Você o substituirá por uma solicitação assíncrona real e mensagens que reflitam o que o estúdio aceitou. Uma página com aparência correta só é uma inscrição quando o serviço preparado devolve a confirmação.

Você precisa de formulários HTML, layout CSS básico, objetos, funções, seleção do DOM e eventos JavaScript. Este laboratório ensina JSON, async/await, fetch, resultados HTTP, estado pendente e mensagens com recuperação. Semântica e restrições condicionais estão preparadas; o laboratório anterior ajuda, mas seus arquivos de VM não são necessários. Edite somente /home/labex/project/stillspoke/request.js e feedback.js. Preserve os demais arquivos, API, capacidade e visitantes. Todas as identidades são sintéticas; não há email ou pagamento. Os 60 minutos são estimativa do autor, não medição com iniciantes.

Use Workspace para substituir arquivos completos e Studio para o site. Study form é um exemplo independente funcional; suas inscrições nunca concluem o trabalho. Studio records lê inscrições aceitas. Practice room é uma página separada que pode recusar uma solicitação antes de aceitar qualquer coisa. Cada laboratório começa com dados independentes. Não ensina o backend preparado, implantação em produção, idempotência de solicitações arbitrárias ou conformidade completa de acessibilidade.

Envie uma solicitação real e espere a resposta

Substitua a demonstração por um POST real, evite ativações duplicadas durante a espera e mostre uma confirmação autêntica do servidor.

Em Studio, escolha Study form. Vá com Tab a Your name e digite Example Guest; Tab a Email, sample@example.test; Tab a Session, digite C e leia Clay, slowly / 10:00. Passe com Tab pela assistência desmarcada e pela nota opcional até Reserve my place. Pressione Enter uma vez. Espere a Confirmation SS-… real, abra Studio records e compare nome, email e hora. Retorne por Back to signup e Work form. O exemplo tem outro banco. Sua página ainda tem apenas visitantes existentes; o texto de demonstração não estabelece aceitação.

O exemplo mostra a confirmação esperada com título próprio e horário legível. Seu número será diferente.

Exemplo independente depois de uma inscrição autêntica

A API preparada pertence ao ambiente local. Seus campos e regras públicos são:

Campo JSON Significado
name Pelo menos dois caracteres após remover espaços externos.
email Endereço sintético terminado em @example.test. O navegador verifica primeiro a sintaxe nativa.
session ID estável publicado: clay-morning para 10:00 ou clay-afternoon para 14:00. A tarde está cheia.
support Booleano indicando seleção de assistência de assento.
note String com ao menos cinco caracteres com assistência, opcional no outro caso.

Um POST envia uma proposta de inscrição a api/bookings. É uma URL relativa à página atual de trabalho ou exemplo, portanto cada uma permanece em seu espaço de negócio. A API retorna JSON, formato textual de objetos, strings, números e booleanos. Nomes de propriedades e strings JSON usam aspas duplas. JSON.stringify(data) converte o objeto JavaScript em texto JSON; response.json() interpreta a resposta como objeto. O cabeçalho Content-Type: application/json informa o conteúdo do corpo. Nem o texto do frontend nem um botão desativado implementam a capacidade do serviço.

Os status HTTP distinguem os resultados:

Status Resposta e fato estabelecido
201 booking contém os campos aceitos, sessionTitle legível e id gerado pelo servidor. Houve aceitação; a confirmação começa com SS-. Nunca a invente.
422 errors associa nomes de campos a explicações. Nada foi inscrito; corrija os campos marcados.
409 A sessão está cheia. Nada foi inscrito; escolha uma disponível.
503 A pausa controlada recusou antes da aceitação. Nada foi inscrito; repetir é seguro.

fetch retorna uma Promise, representando um resultado futuro. Um manipulador async usa await para suspender seu próprio trabalho até a Promise terminar com sucesso ou falha, enquanto o navegador continua utilizável. Espere a resposta HTTP e depois a interpretação JSON. Uma recusa HTTP como 422 ou 503 também resolve fetch; não entra automaticamente em catch. Verifique o status explicitamente. Falha de rede ou interpretação pode entrar em catch sem estabelecer se houve aceitação. A mensagem deve declarar aceitação desconhecida e o caminho de recuperação Studio records.

O evento submit cobre o botão e Enter em um campo. event.preventDefault() impede o envio normal com navegação para permitir JSON. Campos nativamente inválidos param o envio antes do manipulador. form.elements busca por name, não posição visível ou HTML id. Texto usa .value; a caixa usa .checked.

Defina pending antes de qualquer espera. A proteção retorna imediatamente se outro envio chegar durante a espera; .disabled desativa visivelmente o botão nativo. Impede ativações repetidas nesta página durante uma solicitação em andamento, sem garantir isso contra outras páginas ou clientes concorrentes arbitrários. try faz a solicitação; catch informa aceitação desconhecida na falha; finally restaura o botão e limpa o aviso passivo em qualquer resultado. Preserve valores em vez de reiniciar o formulário.

clearErrors, showMessage e showResponse são funções de feedback.js. Após analisar o HTML, a página carrega com defer, nesta ordem, scenario.js, validity.js, feedback.js, request.js. O primeiro fornece dados, o segundo a regra nativa e os últimos cooperam no envio e nas mensagens. O arquivo atual atende o 201 normal; você melhorará recusas de campo depois.

Em Workspace, use cd para escolher o diretório. cat > request.js substitui só esse arquivo. O marcador here-document JS entre aspas deixa o texto literal até a linha com apenas JS; cole todo o bloco sem os acentos graves Markdown. O retorno do prompt indica que foi salvo.

cd /home/labex/project/stillspoke
cat > request.js <<'JS'
const form = document.querySelector('form');
const reserveButton = form.querySelector('[type="submit"]');
const progress = document.querySelector('#progress');
let pending = false;
form.addEventListener('submit', async (event) => {
  event.preventDefault();
  if (pending) return;
  clearErrors();
  document.querySelector('#result').hidden = true;
  const data = {
    name: form.elements.name.value,
    email: form.elements.email.value,
    session: form.elements.session.value,
    support: form.elements.support.checked,
    note: form.elements.note.value
  };
  pending = true;
  reserveButton.disabled = true;
  progress.textContent = 'Sending your request...';
  try {
    const response = await fetch('api/bookings', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    });
    const body = await response.json();
    showResponse(response.status, body);
  } catch (error) {
    showMessage('No confirmation received. Acceptance is unknown. Check Studio records; wait for the original attempt to be resolved before a new submission.');
  } finally {
    pending = false;
    reserveButton.disabled = false;
    progress.textContent = '';
  }
});
JS

Volte a Studio, atualize, digite Morgan Vale, morgan@example.test, escolha Clay, slowly / 10:00 e deixe a assistência desmarcada. Vá com Tab ao botão e pressione Enter uma vez. Durante Sending your request..., ele fica desativado. Espere Submission result mostrar Reserved for Morgan Vale, Confirmation SS-… autêntica e o título legível 10:00. O aviso passivo role="status" nunca recebe foco; a seção comum de resultado pode recebê-lo para facilitar encontrar título e conteúdo.

Escolha Studio records, compare a nova inscrição completa e preserve Existing Visitor e Avery Reed. O ID antigo de demonstração não deve aparecer como registro aceito. Transferência HTTP bem-sucedida não basta: a resposta precisa realmente ser 201, e a confirmação vir do booking aceito. Autoverificação: existe registro real, uma solicitação pendente bloqueia ativações repetidas e o manipulador restaura o botão depois.

Associe a recusa do servidor ao campo certo

Transforme uma recusa de validação real em erro de campo legível sem apagar outras entradas.

O navegador pode recusar sintaxe de email inválida, mas o serviço também tem uma regra de negócio: endereços de prática terminam em @example.test. morgan@other.test é sintaticamente válido, chega ao servidor e gera HTTP 422. É uma solicitação e recusa reais, distintas da mensagem nativa de campo obrigatório.

Uma resposta de erro tem esta forma; são dados para ler, não um comando:

{
  "message": "Please correct the marked fields. Nothing was booked.",
  "errors": {
    "email": "Use an address ending in @example.test for this practice."
  }
}

errors.email aponta à chave API email. Faça a associação por form.elements[name], não pela ordem nem pelo primeiro parágrafo de erro. Uma chave de string entre colchetes seleciona a propriedade correspondente. Object.keys(body.errors) produz um array de nomes; for (const name of ...) percorre cada um. Uma variável let permite reatribuição, então first guarda o primeiro campo marcado.

textContent exibe as strings como texto, sem interpretar mensagens do servidor como HTML. aria-invalid="true" marca um campo inválido; email-error associado fornece motivo visível pelo aria-describedby existente. Não troque a ajuda persistente por cor apenas. Limpar erros antes de novo envio impede uma mensagem velha de descrever um campo corrigido. No 422, mostre o resultado geral e depois foque a primeira entrada marcada. Outros resultados podem focar a seção comum. O anúncio passivo de status ao vivo é outro elemento e não deve ser focado à força.

O sucesso usa template literal: acentos graves envolvem o texto e ${booking.id} insere o valor atual. Isso constrói uma string que textContent mostra literalmente. O número vem da resposta, não é inventado localmente.

Em Workspace, substitua feedback.js pelas funções:

cd /home/labex/project/stillspoke
cat > feedback.js <<'JS'
function clearErrors() {
  for (const field of document.querySelectorAll('form [name]')) {
    field.removeAttribute('aria-invalid');
    const error = document.getElementById(field.name + '-error');
    if (error) error.textContent = '';
  }
}
function showMessage(text) {
  const panel = document.querySelector('#result');
  document.querySelector('#message').textContent = text;
  panel.hidden = false;
  panel.focus();
}
function showResponse(status, body) {
  if (status === 201) {
    const booking = body.booking;
    showMessage(`Reserved for ${booking.name}. Confirmation ${booking.id}. ${booking.sessionTitle}.`);
  } else if (status === 422) {
    showMessage(body.message);
    let first;
    for (const name of Object.keys(body.errors)) {
      const field = document.querySelector('form').elements[name];
      document.getElementById(name + '-error').textContent = body.errors[name];
      field.setAttribute('aria-invalid', 'true');
      if (!first) first = field;
    }
    first.focus();
  } else {
    showMessage(body.message);
  }
}
JS

Volte a Studio, atualize, preencha Morgan Vale, morgan@other.test, Clay, slowly / 10:00, assistência marcada e A seat near the entrance. Envie uma vez. Deve aparecer Nothing was booked geral e um novo erro específico do email. O foco vai a Email; rótulo e ajuda permanecem, assim como nome, sessão, caixa e nota. Studio records não deve adicionar inscrição para o endereço recusado. Para olhar registros sem sair do rascunho, abra Studio records em outra página pelo comando Open Link in New Tab do navegador e volte ao formulário original.

Corrija apenas para morgan@example.test e envie de novo. O erro antigo é limpo, aparece confirmação autêntica e a nota chega ao registro. Teste também outro campo: com o restante válido, substitua o nome por exatamente dois espaços. minlength="2" nativo conta esses caracteres, mas a regra publicada remove espaços externos antes de exigir dois. O verdadeiro 422 deve marcar e focar Your name, não sempre Email, mantendo email, sessão e nota. Restaure Morgan Vale. É permitido repetir o nome sintético em outra inscrição aceita; não é um sistema de unicidade de email. Visitantes antigos permanecem.

Se digitar sem querer morgan.example.test sem @, o navegador recusa antes de POST. É esperado, mas não testa a ramificação 422. Use morgan@other.test, válido para o navegador, para testar a regra do servidor. Se as mensagens não mudam após edição, use cat feedback.js em Workspace, compare o bloco completo, corrija a grafia e atualize Studio. Não apague dados nem reinicie o serviço por uma digitação JavaScript incorreta. Autoverificação: a chave real do servidor corresponde à entrada e ao erro legível certos, o restante sobrevive e corrigir e reenviar funciona.

Recupere-se de sessões cheias e de uma pausa segura

Distinga uma sessão cheia de uma recusa anterior à aceitação, mantenha o rascunho e faça uma repetição segura.

Em Studio, atualize e preencha Casey Brook, casey@example.test, Clay, slowly / 14:00, assistência e A seat near the entrance. Leia o título 14:00 antes de enviar. A primeira C seleciona a primeira opção Clay; outra C passa à seguinte. Leia o valor visível em vez de supor uma posição fixa para a tecla.

Envie uma vez. O serviço retorna HTTP 409 por lotação. Leia That session is full. Nothing was booked; choose another session. Entradas ficam e o botão volta a funcionar. Não remova o visitante 14:00 para abrir vaga. O 409 não precisa de email inválido nem formato incorreto: é uma recusa de negócio a uma proposta válida.

Altere só para Clay, slowly / 10:00. Escolha Practice room, que abre outra página mantendo seu formulário. É treinamento separado da inscrição de clientes. Escolha Pause next submission e espere Next submission will be refused before a booking is accepted. Feche a prática ou volte ao Studio original. Não use Back to signup da prática para substituir seu rascunho ainda aberto.

A página separada declara a promessa de recusa antes da aceitação. Mantenha o formulário original aberto ao usar o controle.

Practice room separada e controle de recusa segura

Envie o original uma vez. Agora vem HTTP 503, explicitando Nothing was booked. Service paused; please retry. Nome, endereço, 10:00, caixa e nota ficam. A solicitação consome a pausa. Com as entradas preservadas, pressione Enter mais uma vez em Reserve my place. Espere o 201 real e confira em Studio records Casey Brook, email, 10:00 e observação. Visitantes e inscrições anteriores permanecem.

O contrato do 503 é restrito: recusa antes de aceitar, tornando essa repetição segura. Conexão perdida ou resposta ilegível é diferente. catch declara aceitação desconhecida, não Nothing was booked. Abra então Studio records em outra página. Um registro correspondente ajuda a localizar uma confirmação, mas nomes e valores repetidos nem sempre identificam a tentativa que o criou. Não envie novamente com a tentativa original pendente de resolução. Mesmo uma leitura bem-sucedida sem correspondência não prova recusa: a solicitação original ainda pode estar em andamento. Aguarde resolução ou consulte o operador do estúdio (instrutor nesta prática). Se os registros não puderem ser lidos, espere também pelo serviço. Só a recusa 503 explicitamente anterior à aceitação estabelece repetição segura aqui. Não há promessa de idempotência nem ensino de pagamentos distribuídos.

Para um erro comum de edição, mude para Workspace e mostre o arquivo salvo:

cd /home/labex/project/stillspoke
cat request.js

Confira a URL relativa exata api/bookings, a grafia JSON.stringify, os dois await e o bloco finally. Se houver erro, substitua pelo bloco completo da etapa 1 e atualize Studio. Antes de nova submissão, resolva tentativas desconhecidas conforme o limite acima; corrigir uma grafia não estabelece que a anterior foi recusada. Quando souber que está resolvida, repita o teste normal pertinente com outro nome sintético. A verificação somente leitura não instala substituto nem faz inscrição real para reparar sua obra.

Autoverificação: lotação e pausa produzem resultados visíveis após a espera, preservam o rascunho, permitem correção ou repetição segura e nunca mostram um número aceito inventado. Redação equivalente compreensível é válida. Uma inscrição normal aceita continua existindo, e a capacidade e os visitantes preparados seguem intactos.

Resumo

Você enviou JSON por POST aguardando a resposta, distinguiu recusa HTTP de incerteza de conexão, protegeu ativações pendentes e exibiu a confirmação realmente aceita. Associou erros aos campos, conservou entradas diante de lotação e pausa e usou registros para orientar recuperação sem supor que toda conexão falha significa que nada foi aceito.