I am trying to develop a simple app with Next.js but i am having issues with learning how to create an api.
This is my component to add an event with a form and a submit method that fetchs the data from the api.
import React from 'react'
import Layout from '#/components/Layout'
import styles from '#/styles/AddEvent.module.css'
export default function AddEventPage() {
const submitHanlder = (e) => {
e.preventDefault();
const formData = {
title: e.target.title.value,
description: e.target.description.value
}
fetch('/api/events', {
method: 'POST',
body: JSON.stringify(formData)
});
console.log(formData)
}
return (
<Layout title='Add New Event'>
<h1>Add Event</h1>
<div className={styles.container}>
<form className={styles.form} action="" onSubmit={submitHanlder}>
<label className={styles.label} >Title</label>
<input type="text" name="title" />
<label className={styles.label} >Description</label>
<input type="text" name="description"/>
<label className={styles.label}htmlFor="">Date</label>
<input type="date" />
<button type='submit' >Submit</button>
</form>
</div>
</Layout>
)
}
And this is my api/events.js:
const handler = (req , res) => {
if(req.method === 'POST'){
return res.status(201).json({ message: 'evento agregado' });
}
return res.status(400).json({ error: 'no se pudo agregar el evento' });
}
export default handler;
It is a simple handler that returns a message depending on the request method, but i am always getting the status 400 with the error message.
This is my request in the browser console:
{"title":"asdasd","description":"asdasdas"}
And my response:
message "evento agregado"
So it seems that is working. But when i go to localhost:3000/api/events it shows the following:
error "no se pudo agregar el evento"
You could try to print out what req.method is when the api gets called.
Add the following statement:
console.log(req.method)`
Then have a look at what the server logs out.
When you try to open localhost:3000/api/events in your browser the browser makes a GET Request, not a POST Request, to your api. That is the default behavior when opening a 'website'.
If you want to test your api you could use Postman or an extension for Visual Studio Code. The REST Client from Visual Studio Marketplace would probably be an option.
Related
I have a vuejs web aplication. In there have a form to edit-user's data. The part of edit the data like 'name', 'phone', etc is working like a charm but when the user come's to the profille picture upload they simply not upload from the backend ( codeigniter4 Rest API ). In the mobile application is everything ok to the update of that. Here is the code:
<form>
<input type="file" #change="`whenSelectImage" />
<div class="button" #click.prevent="atualizarUsuario();uploadFoto()">
<slot>Atualizar informações</slot>
</div>
</form>
and the methods part:
whenSelectImage(event){
this.selectedPicture= event.target.files[0]
},
uploadFoto(){
const fd = new FormData();
fd.append('image', this.selectedPicture, this.selectedPicture.name)
apiOnline
.post(
`/usuario/dados/${window.localStorage.uuid}`, fd
).then(res => {
console.log(res.response.data)
})
.catch(error => console.log(error.response))
}
the console says:
"undefined"
and in the Network Headers they are sending Form Data with Image: ( binary )
I'm using Vuex to store the data of the user
when I execute this in created, it works:
axios
.delete('http://localhost:8000/product/10')
.then(response => {
console.log(response);
})
.catch(err => {
console.log(err);
});
however, if I make a button and on submit I call a method that executes the same code it doesn't work, in the back, I get in the console
OPTIONS /product/10 204 0.172 ms - 0
Note that when I press the button the page refreshes and if I click the button several times fast it executes
Edit: I disabled the refresh, and now it works, Is there anything I can do because I want the method to execute even if I refresh.
the template:
<b-form class="mt-5 pt-5">
<b-form-group id="productId" label="Product id " label-form="productIdInput">
<b-form-input id="productIdInput" type="text" v-model="productForm.id" placeholder="enter product id you wish to delete"> </b-form-input>
</b-form-group>
<button type="button" v-on:click="deleteProduct()">Delete</button>
</b-form>
methods:{
deleteProduct() {
// this.$store.dispatch('removeProduct',this.productForm.id);
axios
.delete('http://localhost:8000/product/10')
.then((response) => {
console.log(response);
})
.catch((err) => {
console.log(err);
})
},
}
The delete request sends options first it seems due to cross-origin and then it waits for response to send the real request, when i click a button and the page refreshes the options is sent, however (what i understood) is that the delete request no longer exists to wait for the response, so simply i added a e.preventDefault() in the method
I have token authentication setup with DRF and VueJS. However, I can't seem to login using the combo of VueJS, axios, and the DRF token system and I don't understand why. I have CORS installed and if I manually set the token into the VueJS code, all my requests from VueJS to the DRF backend API work fine. It's just the login and getting the initial token that isn't working.
Here's my code:
Django URLs:
from rest_framework.authtoken import views
url(r'^api/token-auth/', views.obtain_auth_token)
Django middleware
class SiteLogin:
def process_request(self, request):
url = request.path.split('/')
# Don't require password for the URL /api/token-auth/
if url[1] == 'api' and url[2] == 'token-auth':
return None
auth Service -- VueJS:
// ... other code ...
login (context, creds, redirect) {
console.log(creds)
axios.post(LOGIN_URL, creds).then((response) => {
localStorage.setItem('token', response.data.token)
this.user.authenticated = true
// If a redirect link is provided
if (redirect) {
router.push(redirect)
}
}).catch((err) => {
console.log(err)
})
},
Login Component - VueJS:
<template>
<div>
<div class='container-fluid container-fullw bg-white'>
<div class='row'>
<div class='col-md-4'>
Login<br>
<br>
<input type='text' class='form-control' placeholder="Username" v-model='credentials.username'><br>
<input type='password' class='form-control' placeholder="Password" v-model='credentials.password'><br>
<button class='btn btn-primary btn-sm' #click='submit()'>Login</button>
</div>
</div>
</div>
</div>
</template>
<script>
import auth from '../../services/auth'
export default {
name: 'login',
data () {
return {
credentials: {
username: '',
password: ''
},
error: ''
}
},
methods: {
submit () {
auth.login(this, this.credentials, '/')
}
}
}
</script>
Upon clicking "Submit" the DRF backend always returns a 401.
Edit:
Also, if I add print(request.POST) into the SiteLogin section of the Django middleware, I can see that a) the if statement returns true (it's acknowledging that it's a login URL) and b) the QueryDict is empty -- I see: <QueryDict: {}>
I solved it over here: https://stackoverflow.com/a/45850775/717682
Problem was that the TokenAuthentication was preventing my axios POST request from being called at all -- immediately returning a 401.
I'm trying to authenticate against DRF token.
I've successfully been able to login using an auth app I have created.
I thought I'd be slick and make the login form a component.
Since making it a component however, I'm not able to login and I get an Assertion failure.
My templates/components/auth-login.hbs template looks like so ...
<form class='navbar-form navbar-right' {{action 'authenticate' on='submit'}}>
<div class="form-group">
{{input id='identification' placeholder='Username' type='text' class='form-control' value=identification}}
{{input id='password' placeholder='Password' type='password' class='form-control' value=password}}
</div>
<button type="submit">Login</button>
</form>
I also have app/controllers/auth-login.js
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service(),
actions: {
authenticate: function() {
var credentials = this.getProperties('identification', 'password'),
authenticator = 'authenticator:jwt';
this.get('session').authenticate(authenticator, credentials).catch((reason) => {
this.set('errorMessage', reason.error || reason);
});
}
}
});
It works as an app but not as a component.
If I blank the template, and use the auth route/app instead, it works peachy.
Option 1. You need to define action authenticate in actions hash of auth-login component.
Option 2. You can keep identification, password properties and authenticate action in controller. and include the auth-component like below,
app/templates/application.hbs
{{auth-component identification=identification password=password authenticate="authenticate" }}
app/components/auth-component.js
import Ember from 'ember';
export default Ember.Component.extend({
actions: {
authenticate() {
this.sendAction('authenticate'); //this will call corresonding controller authenticate method through bubbling.
}
}
});
app/controllers/application.js
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service(),
actions: {
authenticate: function() {
var credentials = this.getProperties('identification', 'password'),
authenticator = 'authenticator:jwt';
this.get('session').authenticate(authenticator, credentials).catch((reason) => {
this.set('errorMessage', reason.error || reason);
});
}
}
});
I have this custom login form
<template name="login">
{{> alert}}
<form>
<input type="text" name="username" >
<input type="password" name="password" >
<input type="submit" value="Login" >
</form>
</template>
<template name="alert">
{{alert}}
</template>
I want to put error alert if user failed to login. this is the code to trigger alert message.
Template.login.events({
'submit': function(event){
event.preventDefault();
var usernameVal = event.target.username.value;
var passwordVal = event.target.password.value;
Meteor.loginWithPassword(usernameVal, passwordVal, function(err){
if(err){
Session.set('alert','login failed!');
return false;
}
else{
Session.set('alert',null);
}
});
}
});
Template.alert.helpers({
alert:function(){
return Session.get('alert');
}
});
The problem is when I trigger the error and try to open other page and back to login page, the alert message still there. Alert message only disappear when I refresh my browser or login successfully.
How is the best way to use error handling so the alert message only triggered once. This is including other forms error handling.
Thanks before.
You can clear the Session var when you come back to the view, like this:
Template.login.rendered = function () {
Session.set('alert', null);
};
You can define a timeout on your alerts. Define globally in a "app.js" file if you want this behavior for all your alerts. I got this in my meteor app. Your alerts will stay for 6 secs:
Deps.autorun(function() {
if(Session.get('alert')){
setTimeout(function () {
Session.set('alert','');
}, 6000);
}
});