I wrote an API using django and djano-ninja.
Here is my section of api.py file which is imported to URL.
class ORJSONRenderer(BaseRenderer):
media_type = "application/json"
def render(self, request, data, *, response_status):
return orjson.dumps(data)
class ApiKey(APIKeyQuery):
param_name = "api_key"
def authenticate(self, request, key):
try:
return CustomUser.objects.get(api_key=key)
except CustomUser.DoesNotExist:
pass
api_key = ApiKey()
api = NinjaAPI(
title="Good TExt",
version="0.0.1",
description="That This",
renderer=ORJSONRenderer(),
# csrf=True
)
#api.patch(
"/car/color/{new_color}", auth=api_key, tags=["Car"], summary="Does something",
description="Does something"
)
def update_team_name(request, new_color):
try:
#Do something
msg = {"success": "Done"}
except:
msg = {"error": "Problem"}
return HttpResponse(json.dumps(msg), content_type='application/json')
I have other get endpoints too. There is no problem when I request get endpoints.
But when I send a request to patch endpoints I am getting 401 (Unauthorized) only with ajax. I mean python's requests work.
import requests
load = dict(
api_key='SOME HEY'
)
r = requests.get("http://127.0.0.1:8000/api/car/color/red", params=load)
print(r.text)
But javascript doesn't:
$.ajax({
url: "/api/car/color/red",
data: {
"api_key": "some key"
},
cache: false,
type: "PATCH",
success: function(response_country) {
console.log(response_country);
},
error: function(xhr) {
console.log(xhr);
}
});
What I did try
I tried to add:
headers:{"X-CSRFToken": $crf_token},
to header of the ajax request. Even though csrf is set to False in django-ninja
I tried to change from PATCH to PUT
I tried to add a timeout to ajax request
I tried to send the api_key trough header and not the data
with no success.
Related
Basically, I am using http-request-plugin to send http-request in jenkins-pipeline.
In this post, it is possible to send JSON-encoded http-body in http-get method. However, the http-body is empty in the server-side when running the below jenkins-pipeline script. Is it allowed to send JSON-data in http-body when using http-get method?
import groovy.json.JsonOutput
def reqBody = [
'key01': 'val01',
'key02': 'val02',
]
def resp = httpRequest(
url: '127.0.0.1:8000/api/service01',
httpMode: 'GET',
contentType: 'APPLICATION_JSON',
requestBody: JsonOutput.toJson(reqBody),
)
One possible solution is to refactor the script in the server-side to read parameters in http-post. After this, the http-body has the json-data.
import groovy.json.JsonOutput
def reqBody = [
'key01': 'val01',
'key02': 'val02',
]
def resp = httpRequest(
url: '127.0.0.1:8000/api/service01',
httpMode: 'POST',
contentType: 'APPLICATION_JSON',
requestBody: JsonOutput.toJson(reqBody),
)
I am writing a groovy script which has a method which is invoked from my Jenkins pipeline stage. This function calls an API which has a Basic Auth Header and a post body.
This piece of code returns me 500 on Jenkins, but works correct on Postman.
def callAPI(String SN_CREDENTIALS, String description, String name ) {
String auth = SN_CREDENTIALS.bytes.encodeBase64().toString()
def body_data = """{
"start_date": "${utc_startdate}",
"end_date": "${utc_enddate}",
"description": "${Description}",
}
"""
def url = 'https://example.com/api/sn_chg_rest/change/standard/' + id
def response = httpRequest url: url, acceptType: 'APPLICATION_JSON',
contentType: 'APPLICATION_JSON',
httpMode: 'POST',
requestBody: body_data,
customHeaders: [[name: 'Authorization', value: "Basic ${auth}"]]
}
where SN_CREDENTIALS are the credentials saved on Jenkins.
Jenkinsfile
environment {
SN_CREDENTIALS = credentials('SNCreds')
}
stage{
steps{
script{
buildTicketScript.callAPI("${SN_CREDENTIALS}",description,name)
}
}
}
Response Code: HTTP/1.1 500 Internal Server Error
Is there something wrong with the piece of code?
I found the issue. There was a problem with my body_data, one of the values had "new line" and it wasn't parsing it correctly. Removed the new line and it works perfectly fine
I want to scrape all 'belts' from https://www.thingiverse.com/thing:3270948/remixes in Scrapy.
First of all I want write proper request.
I tryied:
scrapy.FormRequest(url="https://www.thingiverse.com/thing:3270948/remixes",
method="POST",
formdata={
'page': '7',
'id': '3270948'},
headers={
'x-requested-with': 'XMLHttpRequest',
'content-type':
['application/x-www-form-urlencoded',
'charset=UTF-8']}
Response contain only first page(24 belts). How write proper request to get next/whole belts?
You have more parameters in request payload, I've copied them all from Network tab:
import scrapy
class TestSpider(scrapy.Spider):
name = 'test'
start_urls = ['https://www.thingiverse.com/thing:3270948/remixes']
ajax_url = 'https://www.thingiverse.com/ajax/things/remixes'
payload = 'id=3270948&auto_scroll=true&page={}&total=153&per_page=24&last_page=7&base_url=%2Fthing%3A3270948%2Fremixes%2F&extra_path=&%24container=.results-container&source=%2Fajax%2Fthings%2Fremixes'
def parse(self, response):
page = response.meta.get('page', 1)
# why 7: check `last_page` param in payload
if page == 7:
return
print '----'
# just to show that content is always different, so pages are different
print page, response.css('div.item-header a span::text').getall()[:3]
print '----'
yield scrapy.Request(self.ajax_url,
method='POST',
headers={
'x-requested-with': 'XMLHttpRequest',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
},
body=self.payload.format(page + 1),
meta={'page': page + 1}
)
According to the Django docs, Django should have csrf token validation enabled by default, using a middleware. When I look in my settings file I indeed see the middleware being included.
However, when I do a post request without a csrf token using Ajax, Django will just allow it. Should it not return an error saying the csrf token is invalid? I am seeing a lot of questions from people who can't get their csrf token validated, but I can't get it INvalidated.
This is my Ajax post function (I collect the data from my inputs with js, and pass it to this function):
function ajaxPost(url, data, success) {
fetch(url, {
method: 'POST', // or 'PUT'
body: JSON.stringify(data),
headers: new Headers({
'Content-Type': 'application/json'
})
}).then(res => res.json())
.then(response => {
if (response.status !== success) {
//errors
}
updateView(response);
})
.catch(error => console.error('Error:', error))
}
And this is my view function:
#api_view(['POST'])
# API endpoint for posting bulk properties
def bulk(request):
new_properties = []
if request.method == 'POST':
for obj in request.data:
discipline = Discipline.objects.get(pk=obj['discipline.id'])
root_function = Function.objects.get(pk=obj['root_function'])
new_property = Property(name=obj['name'], value=obj['value'], unit=obj['unit'],
discipline_id=discipline)
new_property.save()
new_property.function.add(root_function)
new_properties.append(new_property)
new_properties = json.loads(serializers.serialize('json', new_properties))
return JsonResponse({'status': 201, 'new_properties': new_properties})
Assuming api_view is the one from django-rest-framework, it disables CSRF protection for that view.
This is because API endpoints are frequently used for external requests that won't have a CSRF token; there's no point checking for it in these cases.
I'm passing a ajax call to update data in my application through twitter bootstrap modal window. The ajax code is given below:
$(document).ready(function(){
var link=$('#link_hash').val();
$("#update_link").click(function(){
console.log("I'm here");
$.ajax({
url: "profiles/update_link",
type: "POST",
dataType: "html",
data: {link: link,data: $('#link_hash').val() },
success: function(data) {
// some code
},
error: function(data1) {
// some code
}
});
});
});
I have modifies route.rb file to match it to my controllers "update_link" method.
The code in my method is given below:-
def update_link
#link=Link.find_by_link(params[:link])
#tlink=Link.find_by_link(params[:data])
logger.info "=========kkkkkkkkkkkkkk=================================#{#link.inspect}"
logger.info "=========kkkkkkkkkkkkkk=================================#{#tlink.inspect}"
logger.info "=========kkkkkkkkkkkkkk=================================#{params.inspect}"
respond_to do |format|
if #tlink.nil?
#link.update_attributes(:link => params[:data])
...some code....
else
...some code...
end
end
end
end
So in the server log it's showing -
Started POST "/profiles/update_link" for 127.0.0.1 at 2013-02-20 12:08:20 +0530
Processing by ProfilesController#update_link as HTML
Parameters: {"link"=>"9bfzjp", "data"=>"9bfzjpaaa"}
WARNING: Can't verify CSRF token authenticity
Completed 401 Unauthorized in 6ms
So clearly "logger.info" is not showing up...Now after searching I was able to solve the WARNING but still 401 is present...How to solve this??
Thanks in advance....
According to your server log, you are not passing CSRF token, so rails automatically considers request to be malicious and flags it as unverified. default handling of unverified requests is to reset session. Can you comment out protect_from_forgery or add skip_before_filter :verify_authenticity_token to your controller to see if it the case?
If you want to include authenticity token in your ajax request (highly recommended) you can add it to headers in your ajax request:
headers: {
'X-Transaction': 'POST Example',
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
}
Add skip_before_filter :authenticate_user! to your controller.