To the Server!

In the previous episode, we created a new post but we still need to send it to the server. We’ll add some code to do that now in api.js.

// api.js
export function create(post) {
  const request = {
    url: '/posts.json',
    method: 'post',
    data: {post},
  }
  return axios(request)
      .then(response => console.log(response.data))
      .catch(error => console.log(error))
}

And we’ll link it to the post editor in Main.js.

export function Main() {
  return <div id='main'>
      <Editor onSubmit={create} />
      <Post id={1}/>
    </div>
}

Let’s give it a try…

Oh, dear! The console says…

POST http://blogging.local:3000/posts.json 422 (Unprocessable Entity)

…and the rails log says the problem is ActionController::InvalidAuthenticityToken.

Rails adds the CSRF token to forms automatically but we need to take care of that ourselves in this brave new world. The default rails layout adds the CSRF token to the header and we can access it with this code.

export function getCSRFToken() {
  const csrfTag = document.querySelector('meta[name=csrf-token]') 
  return csrfTag?.content || 'missing-csrf-token'
}

We’ll add it to our request like this.

    const request = {
      url: '/posts.json',
      method: 'post',
      data: {post},
      headers: {
        'X-CSRF-Token': getCSRFToken(),
      }
    }

I try again and now my post succeeds. The result shows up in the console. Huzzah!

{id: 28, title: "New post", body: "with a body", created_at: "2021-04-17T13:26:38.531Z", updated_at: "2021-04-17T13:26:38.531Z"}

It would be lovely if our new post showed up on the screen — and we’ll get to that in a bit — but let’s do some tidying first.

I’ll move the post code to server.js and consolidate get with post.

class Server {
  get(url)        { return this.send(url)}
  post(url, data) { return this.send(url, 'post', data) }

  send(url, method, data) {
    const request = {
      url: url,
      method: method,
      data: data,
      headers: {
        'X-CSRF-Token': getCSRFToken(),
      }
    }
    return axios(request)
        .then(response => response.data)
        .catch(error => console.log(error))
  }
}

export const server = new Server()

So now the code in api.js is just…

export function fetch(id) {
  return server.get(`/posts/${id}.json`)
}
export function create(post) {
  return server.post('/posts.json', {post})
}

To recap, we can display a single post and we can create a new post. Let’s show a list of all the posts next.