Closed mettok closed 3 years ago
I understand! could you use exclusions in your pom/gradle when importing spring-boot-rest-api-helpers ? assuming you won't use spring security. Another option would be to configure the spring security so that it permits all requests and doesnt need authorization/authentication..
I would suggest to keep the wrapper that puts everything in content since this is compatible with pagination and on top of that protects from some old security issues when returning a json array directly.
I tried exclusion but i ran into some compiling problem, since the package is imported to the context. Yeah i would keep the wrapper but then i couldnt use simplerestDataprovider on react admin. Do you suggest any other dataprovider which is compatible?
I have made one dataprovider specifically for these helpers in most of my projects I can share it with you the next days. Try to add spring security but permitAll() for all requests or create your own wrapper (controlleradvice) with just the things you need, so you dont have a problem with it
On Tue, Feb 18, 2020, 09:36 mettok notifications@github.com wrote:
I tried exclusion but i ran into some compiling problem, since the package is imported to the context. Yeah i would keep the wrapper but then i couldnt use simplerestDataprovider on react admin. Do you suggest any other dataprovider which is compatible?
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/zifnab87/spring-boot-rest-api-helpers/issues/6?email_source=notifications&email_token=AAEAN3TV6UO4PEJJPJ2HAILRDOFYLA5CNFSM4KW55BLKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEMA5EEA#issuecomment-587321872, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAEAN3TJEGTYSDJ7XZXZ72DRDOFYLANCNFSM4KW55BLA .
Sorry for the delay when I tried 2-3 days ago comments were not working .. Here is a sample of what I usually use as a dataProvider:
import {
GET_LIST,
GET_ONE,
GET_MANY,
GET_MANY_REFERENCE,
CREATE,
UPDATE,
DELETE,
DELETE_MANY,
fetchUtils,
} from 'react-admin';
import { stringify } from 'query-string';
import config from './config/config';
console.log(config);
const API_URL = config.baseUrl;
const HOST = config.apiHost;
/**
* @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
* @param {String} resource Name of the resource to fetch, e.g. 'posts'
* @param {Object} params The Data Provider request params, depending on the type
* @returns {Object} { url, options } The HTTP request parameters
*/
let keysContainingFilePaths = ['avatarPhotos', 'galleryPhotos'];
let referenceManyToOneKeys = {
"wines": ["wineSupplier","wineColor","wineType", "wineDryness", "wineBottleVolume",
"wineSpecialType", "wineOrigin"]
}
let referenceManyToManyKeys = {
"wines": ["varieties","foodCombinations"]
}
const convertDataProviderRequestToHTTP = (type, resource, params) => {
switch (type) {
case GET_LIST: {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([page - 1,perPage]),
filter: JSON.stringify(params.filter),
};
return { url: `${API_URL}/${resource}?${stringify(query)}` };
}
case GET_ONE:
return { url: `${API_URL}/${resource}/${params.id}` };
case GET_MANY: {
const query = {
filter: JSON.stringify({ id: params.ids }),
};
return { url: `${API_URL}/${resource}?${stringify(query)}` };
}
case GET_MANY_REFERENCE: {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([page - 1 , perPage]),
filter: JSON.stringify({ ...params.filter, [params.target]: params.id }),
};
return { url: `${API_URL}/${resource}?${stringify(query)}` };
}
case UPDATE:
return {
url: `${API_URL}/${resource}/${params.id}`,
options: { method: 'PUT', body: JSON.stringify( upsertOneRequestHelper(params.data, keysContainingFilePaths, resource)) },
};
case CREATE:
return {
url: `${API_URL}/${resource}`,
options: { method: 'POST', body: JSON.stringify( upsertOneRequestHelper(params.data, keysContainingFilePaths, resource)) },
};
case DELETE:
return {
url: `${API_URL}/${resource}/${params.id}`,
options: { method: 'DELETE' },
};
case DELETE_MANY:
return {
url: `${API_URL}/${resource}/${params.ids[0]}`,
options: { method: 'DELETE' },
};
default:
throw new Error(`Unsupported fetch action type ${type}`);
}
};
const upsertOneRequestHelper = (row, fileKeys, resource) => {
let request = {};
Object.keys(row).forEach(function(key) {
let valIsFilePath = fileKeys.indexOf(key) > -1;
let isManyToOneKey = (referenceManyToOneKeys[resource])?referenceManyToOneKeys[resource].indexOf(key) > -1: false;
let isManyToManyKey = (referenceManyToManyKeys[resource])?referenceManyToManyKeys[resource].indexOf(key) > -1: false;
if (valIsFilePath && row[key] instanceof Array) {
let values = row[key];
request[key] = [];
for (let val of values) {
request[key].push({ "id": val });
}
}
else if(isManyToOneKey) {
request[key] = (row[key])? {id: row[key]} : null;
}
else if(isManyToManyKey) {
request[key] = (row[key])? row[key].map((id)=> { return {id: id}}) : [];
}
else {
request[key] = row[key];
}
});
return request;
}
const getOneRowResponseHelper = (row, fileKeys, rowInList, resource) => {
let result = {};
Object.keys(row).forEach(function(key) {
let valIsFilePath = fileKeys.indexOf(key) > -1;
let isManyToOneKey = (referenceManyToOneKeys[resource])?referenceManyToOneKeys[resource].indexOf(key) > -1: false;
let isManyToManyKey = (referenceManyToManyKeys[resource])?referenceManyToManyKeys[resource].indexOf(key) > -1: false;
if (valIsFilePath && row[key] instanceof Array) {
let values = row[key];
result[key] = [];
for (let val of values) {
result[key].push({ "id": val.id, "path": HOST +'/'+ val.relativePath +'/'+ val.fileName });
}
}
else if(isManyToOneKey) {
result[key] = (row[key])? row[key].id : null;
}
else if(isManyToManyKey) {
result[key] = row[key]? row[key].map((obj)=> {return obj.id}) : [];
}
else {
result[key] = row[key];
}
});
return result;
}
const prepareGetListResponse = (rows, resource) => {
let result = rows.map(function (row) {
return getOneRowResponseHelper(row, keysContainingFilePaths, true, resource);
});
return result;
}
/**
* @param {Object} response HTTP response from fetch()
* @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
* @param {String} resource Name of the resource to fetch, e.g. 'posts'
* @param {Object} params The Data Provider request params, depending on the type
* @returns {Object} Data Provider response
*/
const convertHTTPResponseToDataProvider = (response, type, resource, params) => {
const { headers, json } = response;
switch (type) {
case GET_LIST:
case GET_MANY:
return {
data: prepareGetListResponse(json.content.map(x => x), resource),
total: parseInt(json.totalElements, 10)
};
case CREATE:
return { data: { ...params.data, id: json.id } };
default:
return { data: getOneRowResponseHelper(json, keysContainingFilePaths, false, resource)};
}
};
/**
* @param {string} type Request type, e.g GET_LIST
* @param {string} resource Resource name, e.g. "posts"
* @param {Object} payload Request parameters. Depends on the request type
* @returns {Promise} the Promise for response
*/
export default (type, resource, params) => {
const { fetchJson } = fetchUtils;
let { url, options } = convertDataProviderRequestToHTTP(type, resource, params);
if (!options) {
options = {};
}
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
let jwt_token = localStorage.getItem('jwt_token');
options.headers.append('Authorization','Bearer ' + jwt_token);
return fetchJson(url, options)
.then(response => convertHTTPResponseToDataProvider(response, type, resource, params));
};
spring security shouldn't be a problem anymore
Hi Thank for making this code available. It was a big help for me. there are some issue though. Spring security is included because of one exception handler. if you import this api into a spring boot app without spring security you will have authorize first. and i ran into another problem with Swagger which not working anymore. I needed to download the source code and and comment out the line which uses spring security. I tried to use simpleRestProvider, but this api is not compatible. i needed to do some modification and put the data into the root element of json response instead of wrap it into content, maybe i do something wrong, but i needed to do that to make it work.