I cannot find the way to execute this code properly with UNIX:
package main
import (
"time"
"github.com/gin-gonic/gin"
"net/http"
)
type Things struct {
Name string `json:"name"`
OneDay time.Time `json:"oneDay"`
}
type Example struct {
Things []Things `json:"things"`
Something int `json:"something"`
}
func TestGinGo(c *gin.Context) {
var example Example
c.BindJSON(&example)
c.JSON(http.StatusOK, gin.H{"data": example})
}
func main() {
r := gin.Default()
r.POST("/", TestGinGo)
r.Run("0.0.0.0:8080")
}
I call this endpoint like this:
curl --location --request POST 'localhost:8080' \
--header 'Content-Type: application/json' \
--data-raw '{
"things": [{
"name": "bling",
"oneDay": "2020-01-01T00:00:00Z"
}],
"something": 2
}'
The response is correct:
{
"data": {
"things": [
{
"name": "bling",
"oneDay": "2020-01-01T00:00:00Z"
}
],
"something": 2
}
}
Now I change slightly the code to work with UNIX like this:
package main
import (
"time"
"github.com/gin-gonic/gin"
"net/http"
)
type Things struct {
Name string `json:"name"`
OneDay time.Time `json:"oneDay" time_format:"unix"`
}
type Example struct {
Things []Things `json:"things"`
Something int `json:"something"`
}
func TestGinGo(c *gin.Context) {
var example Example
c.BindJSON(&example)
c.JSON(http.StatusOK, gin.H{"data": example})
}
func main() {
r := gin.Default()
r.POST("/", TestGinGo)
r.Run("0.0.0.0:8080")
}
And I call it like this:
curl --location --request POST 'localhost:8080' \
--header 'Content-Type: application/json' \
--data-raw '{
"things": [{
"name": "bling",
"oneDay": 1589898758007
}],
"something": 2
}'
And I get this error now (400 bad format):
{"data":{"things":[{"name":"bling","oneDay":"0001-01-01T00:00:00Z"}],"something":0}}
I get into the library... and I see that the code is there to use "unix":
https://github.com/gin-gonic/gin/blob/master/binding/form_mapping.go#L272
I would really like to use unix, because many languages don't need a library for using unix, and I don't want to force an specific format to be used by consumer... And I don't see where I am missing the ball here...
time_format tag is only used in form binding, not json;
You can use custom Marshal and Unmarshal functions (see https://pkg.go.dev/encoding/json#example-package-CustomMarshalJSON)
package main
import (
"encoding/json"
"github.com/gin-gonic/gin"
"log"
"net/http"
"time"
)
type myTime time.Time
func (mt *myTime) UnmarshalJSON(bs []byte) error {
var timestamp int64
err := json.Unmarshal(bs, ×tamp)
if err != nil {
return err
}
*mt = myTime(time.Unix(timestamp/1000, timestamp%1000*1e6))
return nil
}
func (mt myTime) MarshalJSON() ([]byte, error) {
timestamp := time.Time(mt).UnixNano() / 1e6
log.Println(time.Time(mt).UnixNano())
return json.Marshal(timestamp)
}
type Timestamp struct {
OneDay myTime `json:"oneDay" form:"oneDay"`
AnotherDay time.Time `json:"anotherDay" form:"anotherDay" time_format:"unix"`
}
func parseTime(c *gin.Context) {
var example Timestamp
if err := c.Bind(&example); err != nil {
log.Printf("bind timestamp error: %s", err)
}
c.JSON(http.StatusOK, gin.H{"data": example})
}
func main() {
r := gin.Default()
r.POST("/time", parseTime)
r.Run("0.0.0.0:8080")
}
send as json
curl --location --request POST 'localhost:8080/time' \
--header 'Content-Type: application/json' \
--data '{
"oneDay": 1589898758007,
"anotherDay": "1589898758"
}'
oneDay is right, anotherDay doesn't work
{"data":{"oneDay":1589898758007,"anotherDay":"0001-01-01T00:00:00Z"}}
send as form
curl --location --request POST 'localhost:8080/time' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data 'oneDay=1589898758007&anotherDay=1589898758'
both are right
{"data":{"oneDay":1589898758007,"anotherDay":"2020-05-19T22:32:38+08:00"}}
//Send put request with given params
func SendPostRequest(url string, param map[string]interface{}, authToken string) string{
//to disable security check
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
//Parse to json
jsonValue, _ := json.Marshal(param)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonValue))
req.Header.Add("Content-Type", "application/json")
req.Header.Add("AuthToken", authToken)
client := &http.Client{}
resp, err := client.Do(req)
}
Here is the JSON file
{"credentials":{"display_name":"win10Test","is_default":"","password":"","username":""},
"defaultschedule":true,"host_info":{"ip":"*.*.*.*"},
"install_agent":false,"is_auth_enabled":false,"is_enabled":true,"is_encrypted":false,
"is_synchable":false,"name":"win10","os_type":"Windows","priority":300,"use_ssl":false}
When I run the code, I am getting the following error
response Status: 403 Forbidden
403 is Forbidden request - https://en.wikipedia.org/wiki/HTTP_403
I think you send wrong authToken
Check it more carefully.
UPDATED Question:
I got in touch with the WhenIWork Team and discovered that they need the username and password to be passed in the body but with our a form. So I have solved. If you look at the answer below, it works.
Thanks everyone!
I am trying to get the access token from WhenIWork using Swift and Alamofire on Xcode, the json returned Success but says "Application Not Found Error"
I've been looking for documentation from WhenIWork Doc but without success on error code. (They don't have any error in the 1xxx range)
Ideas? I am new to Swift (and coding in general) so any help would be appreciated.
Thanks!
Below is the Terminal answer:
SUCCESS: {
code = 1110;
error = "Application not found";
}
[Request]: POST https://api.wheniwork.com/2/login/
[Response]: <NSHTTPURLResponse: 0x6080000325e0> { URL: https://api.wheniwork.com/2/login/ } { status code: 401, headers {
"Access-Control-Allow-Headers" = "Authorization, Origin, X-Requested-With, W-Date-Format, Content-Type, Accept, W-Token, W-UserId, W-Key, branch";
"Access-Control-Allow-Methods" = "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS";
"Access-Control-Allow-Origin" = "*";
"Cache-Control" = "no-cache";
Connection = "keep-alive";
"Content-Type" = "application/json";
Date = "Thu, 17 Aug 2017 17:11:08 GMT";
Server = nginx;
"Transfer-Encoding" = Identity;
"X-Database" = ro;
"X-State" = "RequestId: 0f853dd4-836f-11e7-90f4-0242e14cb0c5, LoginId: 0, AccountId: 0";
"X-Timer-Database" = "0.0052359104156494";
"X-Timer-Total" = "0.012078046798706";
} }
Code:
func logInWhenIWork() {
let parameters: Parameters = [
"username": "cxxxx#xxxx.ca",
"password": "xxxxxxx",
"W-Key": "xxxxxxxxxxxxxsxx"
]
Alamofire.request("https://api.wheniwork.com/2/login", method: .post, parameters: parameters, encoding: JSONEncoding.default).responseJSON { response in
print(response)
debugPrint(response)
if let json = response.result.value {
print("JSON: \(json)")
} else {
print(response)
}
}
I don't use Alamofire much but I tried the following:
let parameters = ["username":"user#example.com",
"password": "*******"]
let headers = ["W-Key": "iworksoharditsnotfunny"]
var req = Alamofire.request("https://api.wheniwork.com/2/login",
parameters: parameters,
encoding: JSONEncoding.default,
headers: headers)
The request ends up looking like this:
curl -v \
-H "Content-Type: application/json" \
-H "Accept-Language: en-US;q=1.0" \
-H "User-Agent: Unknown/Unknown (Unknown; build:Unknown; OS X 10.12.6) Alamofire/1.0" \
-H "W-Key: iworksoharditsnotfunny" \
-H "Accept-Encoding: gzip;q=1.0, compress;q=0.5" \
-d "{\"username\":\"user#example.com\",\"password\":\"*******\"}" \
"https://api.wheniwork.com/2/login"
Which seems to pretty much match the example given in the WhenIWork API documentation. I don't have an account so I can't test it directly.
For those of you who wanted the answer. I finally figured it out. Here it is
func logInWhenIWork() {
let url = URL(string: "https://api.wheniwork.com/2/login")!
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.allHTTPHeaderFields = ["W-Key": "xxxxxxxxxxx","Content-Type":"application/json"]
let parameters = ["username": "ss#xxx.ca", "password": "sssdsds"]
do {
urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
} catch {
// No-op
}
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
Alamofire.request(urlRequest).responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
// print("JSON: (json)")
let token = json["token"].stringValue
let newUserID = json["users"][0]["id"].int
print(newUserID)
self.wUserID = String(describing: newUserID)
// print(token)
self.wToken = token
if self.wToken != "" {
print("Successfully logged in")
} else {
print("Log In Failed")
}
case .failure(let error):
print(error)
}
}
}
This code works:
func handleFacebookCallback(w http.ResponseWriter, r *http.Request) {
state := r.FormValue("state")
if state != oauthStateString {
fmt.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
code := r.FormValue("code")
////////////////////////////////////////////////////
Url, err := url.Parse(oauthConf.Endpoint.TokenURL)
if err != nil {
log.Fatal("Parse: ", err)
}
parameters := url.Values{}
parameters.Add("client_id", oauthConf.ClientID)
parameters.Add("client_secret", oauthConf.ClientSecret)
parameters.Add("redirect_uri", "http://localhost:9090/oauth2callback")
parameters.Add("code", code)
Url.RawQuery = parameters.Encode()
resp, err := http.Get(Url.String())
if err != nil {
fmt.Printf("Get: %s\n", err)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
defer resp.Body.Close()
But when I replace the part below the marker //////... with:
token, err := oauthConf.Exchange(oauth2.NoContext, code)
if err != nil {
fmt.Printf("oauthConf.Exchange() failed with '%s'\n", err)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
I get:
oauthConf.Exchange() failed with 'oauth2: cannot fetch token: 400 Bad
Request Response: {"error":{"message":"Missing redirect_uri
parameter.","type":"OAuthException","code":191,"fbtrace_id":"XXXX"}}'
Is the package golang.org/x/oauth2 unable to exchange a code for a token?
I found out what was missing. I apparently need to add the RedirectURLfield in the oauthConfig struct to get Exchange() to work properly. This is not the case for Slack or GitHub but apparently FB is slightly more picky.
var oauthConf = &oauth2.Config{
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
RedirectURL: "http://localhost:9090/oauth2callback", /* Fixed! */
Scopes: []string{"public_profile"},
Endpoint: facebook.Endpoint,
}
In Node.js, other than using child process to make CURL call, is there a way to make CURL call to remote server REST API and get the return data?
I also need to set up the request header to the remote REST call, and also query string as well in GET (or POST).
I find this one: http://blog.nodejitsu.com/jsdom-jquery-in-5-lines-on-nodejs
but it doesn't show any way to POST query string.
Look at http.request
var options = {
host: url,
port: 80,
path: '/resource?id=foo&bar=baz',
method: 'POST'
};
http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
}).end();
How about using Request — Simplified HTTP client.
Edit February 2020: Request has been deprecated so you probably shouldn't use it any more.
Here's a GET:
var request = require('request');
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body) // Print the google web page.
}
})
OP also wanted a POST:
request.post('http://service.com/upload', {form:{key:'value'}})
I use node-fetch because it uses the familiar (if you are a web developer) fetch() API. fetch() is the new way to make arbitrary HTTP requests from the browser.
Yes I know this is a node js question, but don't we want to reduce the number of API's developers have to memorize and understand, and improve re-useability of our javascript code? Fetch is a standard so how about we converge on that?
The other nice thing about fetch() is that it returns a javascript Promise, so you can write async code like this:
let fetch = require('node-fetch');
fetch('http://localhost', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: '{}'
}).then(response => {
return response.json();
}).catch(err => {console.log(err);});
Fetch superseeds XMLHTTPRequest. Here's some more info.
Look at http://isolasoftware.it/2012/05/28/call-rest-api-with-node-js/
var https = require('https');
/**
* HOW TO Make an HTTP Call - GET
*/
// options for GET
var optionsget = {
host : 'graph.facebook.com', // here only the domain name
// (no http/https !)
port : 443,
path : '/youscada', // the rest of the url with parameters if needed
method : 'GET' // do GET
};
console.info('Options prepared:');
console.info(optionsget);
console.info('Do the GET call');
// do the GET request
var reqGet = https.request(optionsget, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('GET result:\n');
process.stdout.write(d);
console.info('\n\nCall completed');
});
});
reqGet.end();
reqGet.on('error', function(e) {
console.error(e);
});
/**
* HOW TO Make an HTTP Call - POST
*/
// do a POST request
// create the JSON object
jsonObject = JSON.stringify({
"message" : "The web of things is approaching, let do some tests to be ready!",
"name" : "Test message posted with node.js",
"caption" : "Some tests with node.js",
"link" : "http://www.youscada.com",
"description" : "this is a description",
"picture" : "http://youscada.com/wp-content/uploads/2012/05/logo2.png",
"actions" : [ {
"name" : "youSCADA",
"link" : "http://www.youscada.com"
} ]
});
// prepare the header
var postheaders = {
'Content-Type' : 'application/json',
'Content-Length' : Buffer.byteLength(jsonObject, 'utf8')
};
// the post options
var optionspost = {
host : 'graph.facebook.com',
port : 443,
path : '/youscada/feed?access_token=your_api_key',
method : 'POST',
headers : postheaders
};
console.info('Options prepared:');
console.info(optionspost);
console.info('Do the POST call');
// do the POST call
var reqPost = https.request(optionspost, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('POST result:\n');
process.stdout.write(d);
console.info('\n\nPOST completed');
});
});
// write the json data
reqPost.write(jsonObject);
reqPost.end();
reqPost.on('error', function(e) {
console.error(e);
});
/**
* Get Message - GET
*/
// options for GET
var optionsgetmsg = {
host : 'graph.facebook.com', // here only the domain name
// (no http/https !)
port : 443,
path : '/youscada/feed?access_token=you_api_key', // the rest of the url with parameters if needed
method : 'GET' // do GET
};
console.info('Options prepared:');
console.info(optionsgetmsg);
console.info('Do the GET call');
// do the GET request
var reqGet = https.request(optionsgetmsg, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('GET result after POST:\n');
process.stdout.write(d);
console.info('\n\nCall completed');
});
});
reqGet.end();
reqGet.on('error', function(e) {
console.error(e);
});
Axios
An example (axios_example.js) using Axios in Node.js:
const axios = require('axios');
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
app.get('/search', function(req, res) {
let query = req.query.queryStr;
let url = `https://your.service.org?query=${query}`;
axios({
method:'get',
url,
auth: {
username: 'the_username',
password: 'the_password'
}
})
.then(function (response) {
res.send(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
});
var server = app.listen(port);
Be sure in your project directory you do:
npm init
npm install express
npm install axios
node axios_example.js
You can then test the Node.js REST API using your browser at: http://localhost:5000/search?queryStr=xxxxxxxxx
Similarly you can do post, such as:
axios({
method: 'post',
url: 'https://your.service.org/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
SuperAgent
Similarly you can use SuperAgent.
superagent.get('https://your.service.org?query=xxxx')
.end((err, response) => {
if (err) { return console.log(err); }
res.send(JSON.stringify(response.body));
});
And if you want to do basic authentication:
superagent.get('https://your.service.org?query=xxxx')
.auth('the_username', 'the_password')
.end((err, response) => {
if (err) { return console.log(err); }
res.send(JSON.stringify(response.body));
});
Ref:
https://github.com/axios/axios
https://www.twilio.com/blog/2017/08/http-requests-in-node-js.html
I have been using restler for making webservices call, works like charm and is pretty neat.
To use latest Async/Await features
https://www.npmjs.com/package/request-promise-native
npm install --save request
npm install --save request-promise-native
//code
async function getData (){
try{
var rp = require ('request-promise-native');
var options = {
uri:'https://reqres.in/api/users/2',
json:true
};
var response = await rp(options);
return response;
}catch(error){
throw error;
}
}
try{
console.log(getData());
}catch(error){
console.log(error);
}
Warning: As of Feb 11th 2020, request is fully deprecated.
One another example - you need to install request module for that
var request = require('request');
function get_trustyou(trust_you_id, callback) {
var options = {
uri : 'https://api.trustyou.com/hotels/'+trust_you_id+'/seal.json',
method : 'GET'
};
var res = '';
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
res = body;
}
else {
res = 'Not Found';
}
callback(res);
});
}
get_trustyou("674fa44c-1fbd-4275-aa72-a20f262372cd", function(resp){
console.log(resp);
});
const http = require('http');
const url = process.argv[2];
http.get(url, function(response) {
let finalData = "";
response.on("data", function (data) {
finalData += data.toString();
});
response.on("end", function() {
console.log(finalData.length);
console.log(finalData.toString());
});
});
I didn't find any with cURL so I wrote a wrapper around node-libcurl and can be found at https://www.npmjs.com/package/vps-rest-client.
To make a POST is like so:
var host = 'https://api.budgetvm.com/v2/dns/record';
var key = 'some___key';
var domain_id = 'some___id';
var rest = require('vps-rest-client');
var client = rest.createClient(key, {
verbose: false
});
var post = {
domain: domain_id,
record: 'test.example.net',
type: 'A',
content: '111.111.111.111'
};
client.post(host, post).then(function(resp) {
console.info(resp);
if (resp.success === true) {
// some action
}
client.close();
}).catch((err) => console.info(err));
If you have Node.js 4.4+, take a look at reqclient, it allows you to make calls and log the requests in cURL style, so you can easily check and reproduce the calls outside the application.
Returns Promise objects instead of pass simple callbacks, so you can handle the result in a more "fashion" way, chain the result easily, and handle errors in a standard way. Also removes a lot of boilerplate configurations on each request: base URL, time out, content type format, default headers, parameters and query binding in the URL, and basic cache features.
This is an example of how to initialize it, make a call and log the operation with curl style:
var RequestClient = require("reqclient").RequestClient;
var client = new RequestClient({
baseUrl:"http://baseurl.com/api/", debugRequest:true, debugResponse:true});
client.post("client/orders", {"client": 1234, "ref_id": "A987"},{"x-token": "AFF01XX"});
This will log in the console...
[Requesting client/orders]-> -X POST http://baseurl.com/api/client/orders -d '{"client": 1234, "ref_id": "A987"}' -H '{"x-token": "AFF01XX"}' -H Content-Type:application/json
And when the response is returned ...
[Response client/orders]<- Status 200 - {"orderId": 1320934}
This is an example of how to handle the response with the promise object:
client.get("reports/clients")
.then(function(response) {
// Do something with the result
}).catch(console.error); // In case of error ...
Of course, it can be installed with: npm install reqclient.
You can use curlrequest to easily set what time of request you want to do... you can even set headers in the options to "fake" a browser call.
Warning: As of Feb 11th 2020, request is fully deprecated.
If you implement with form-data, for more info (https://tanaikech.github.io/2017/07/27/multipart-post-request-using-node.js):
var fs = require('fs');
var request = require('request');
request.post({
url: 'https://slack.com/api/files.upload',
formData: {
file: fs.createReadStream('sample.zip'),
token: '### access token ###',
filetype: 'zip',
filename: 'samplefilename',
channels: 'sample',
title: 'sampletitle',
},
}, function (error, response, body) {
console.log(body);
});
I found superagent to be really useful,
it is very simple
for example
const superagent=require('superagent')
superagent
.get('google.com')
.set('Authorization','Authorization object')
.set('Accept','application/json')
Update from 2022:
from node.js version v18 on you can use the globally available fetch API (see https://nodejs.org/en/blog/announcements/v18-release-announce/)
There is also an example usage included on their announcement page:
const res = await fetch('https://nodejs.org/api/documentation.json');
if (res.ok) {
const data = await res.json();
console.log(data);
}