Skip to content

Instantly share code, notes, and snippets.

@kvendrik
Last active March 8, 2016 14:37
Show Gist options
  • Select an option

  • Save kvendrik/9fbe775e1644a624589f to your computer and use it in GitHub Desktop.

Select an option

Save kvendrik/9fbe775e1644a624589f to your computer and use it in GitHub Desktop.
API URL parser
const endpoints = {
user: {
get: {
href: "https://api.github.com/user/:id/:name",
templated: true
}
},
articles: {
get: {
href: "https://api.github.com/articles"
}
},
article: {
get: {
href: "https://api.github.com/article/:id",
templated: true
},
post: {
href: "https://api.github.com/article",
params: {
name: "String",
date: "Date",
country: {
state: "String",
name: {
first: "String",
last: {
type: 'String',
optional: true
}
}
}
}
}
}
};
// const apiUrls = new UrlParser(endpoints);
// apiUrls.user.get({ id: 2, name: "matti" }, function(err, res){
// console.log('ohhjaaa');
// });
// apiUrls.article.post({
// name: 'How to be Awesome by Matti',
// date: new Date(),
// country: 'NY'
// }, function(err, res){
// console.log('ohhjaaa');
// });
let parser = new SchemaParser(endpoints.article.post.params)
parser.checkParamsValid({
name: 'How to be Awesome by Matti',
date: new Date(),
country: { state: 'NY', name: { first: 'Matti' } }
});
class SchemaParser {
typeOptions = ["String", "Number", "Date", "Array", "Object", "Boolean"];
constructor(schema){
this._schema = schema;
}
_getValueType(value){
var type = {}.toString.call(value);
return type.match(/\s(\w+)/)[1];
}
checkParamsValid(params){
let schema = this._schema,
self = this;
let checkSchemaObject = function(schemaObj, paramsObj){
//loop all properties in object
for(let key in schemaObj){
//get the schema value, the actual value and the schema type
let schemaVal = schemaObj[key],
paramsVal = paramsObj[key],
objType = self._getValueType(schemaVal);
//if not in given params and not optional, throw error
if(typeof paramsVal === 'undefined' && schemaVal.optional !== true){
throw new Error('Param "'+key+'" is required');
}
//if its an object and has a type option or is a string
//its a schema object/string
var isSchema = (objType === 'Object' && typeof schemaVal.type !== 'undefined');
if(objType === 'String') isSchema = true;
if(isSchema){
let validType = (objType === 'String' ? schemaVal : schemaVal.type),
actualType = self._getValueType(paramsVal);
//if the actual type does not match the type
//it should be
if(actualType !== validType){
if(actualType === 'Undefined' && schemaVal.optional === true){
//dont throw an error as the value is undefined and optional
continue;
}
//value is invalid
throw new Error('Param "'+key+'" should be of type '+validType);
}
} else {
//if its not an object and has no type property and is not a string
//its a custom object
checkSchemaObject(schemaVal, paramsVal);
}
}
};
checkSchemaObject(schema, params);
}
}
class UrlParser {
constructor(endpoints){
this._storeEndpoints(endpoints);
}
_publicsMethods = {
get: function(params, callback, obj){
//get endpoint details
let details = obj._get;
//get parsed endpoint url
let endpointUrl = details.templated ? this._parseEndpointStr(details._cleanHref, params) : details.href;
console.log(endpointUrl);
},
post: function(params, callback, obj){
//get endpoint details
let details = obj._post;
let valid = this._checkParamsSchema(details.params, params);
console.log(endpointUrl);
}
}
_storeEndpoints(endpoints){
//loop endpoints
for(let name in endpoints){
let details = endpoints[name];
//loop request methods
for(let reqMethod in details){
let reqMethodDetails = details[reqMethod];
reqMethodDetails._cleanHref = reqMethodDetails.href.replace(/http(s)?\:\/\//, '');
//save details to different location in object
details['_'+reqMethod] = reqMethodDetails;
//replace method in object with function to use the endpoint
details[reqMethod] = (params, callback) => this._publicsMethods[reqMethod].apply(this, [params, callback, details]);
}
this[name] = details;
}
}
_parseEndpointStr(endpoint, givenParams){
let endpointParamNames = this._getUrlEndpointParamNames(endpoint);
//check if all required params are provided
endpointParamNames.forEach(function(name){
if(typeof givenParams[name] === 'undefined'){
//throw error
throw new Error('Param "'+name+'" is required for endpoint '+endpoint);
}
});
//parse endpoint URL
for(let name in givenParams){
let val = givenParams[name];
endpoint = endpoint.replace(':'+name, val);
}
return endpoint;
}
_getUrlEndpointParamNames(endpoint, params){
let matches = endpoint.match(/\:([^\/\:]+)/g);
matches = matches.map(function(match){
return match.replace(/\:/g, '');
});
return matches
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment