c# - REST API - How To ADD (If Not Exists) Related Records in POST Method? -


the data model

enter image description here

the entities

public class tag {     public int id { get; set; }     public string name { get; set; }     public string urlslug { get; set; } }  public class category {     public int id { get; set; }     public string name { get; set; }     public string urlslug { get; set; } }  public class post {     public int id { get; set; }     public string title { get; set; }     public string urlslug { get; set; }     public string tnimage { get; set; }     public string author { get; set; }     public list<tag> tags { get; set; }     public category category { get; set; }     public string datepublished { get; set; }     public string datecreated { get; set; }     public string datemodified { get; set; }     public string description { get; set; }     public string articlebody { get; set; } } 

i'm using entity-framework against sql server compact embedded db, , have written generic repository crud operations against individual entities post, category, tag etc.

all works fine.

i'm writing asp.net web api expose crud via rest-ful api.

the rest api end points

╔═══════╦═══════════════════════╦════════════════════════════════════╗ ║ verb  ║ end point             ║  description                       ║  ╠═══════╬═══════════════════════╬════════════════════════════════════╣ ║   ║ /api/tags             ║ returns tags                   ║ ║   ║ /api/tags/tips        ║ returns single tag (name=tips)     ║ ║ post  ║ /api/tags             ║ creates new tag                    ║ ║   ║ /api/categories       ║ returns categories             ║ ║   ║ /api/categories/news  ║ returns single category (name=news)║ ║ post  ║ /api/categories       ║ creates new category               ║ ║   ║ /api/posts            ║ returns post                   ║ ║   ║ /api/posts/51         ║ returns single post (id=51)        ║ ║   ║ /api/posts/2/tags     ║ returns tags post w/ id=2      ║ ║   ║ /api/posts/2/category ║ returns category post w/ id=2  ║ ║ post  ║ /api/posts            ║ creates new post                   ║ ╚═══════╩═══════════════════════╩════════════════════════════════════╝ 

the situation

when create post entity doing post request against /api/posts endpoint , have post entities data in body json, potentially have 1 or more tag instances, , 0 or 1 category.

sample post body blog post

{   "title": "how 6 pack abs in 6 days",   "urlslug": "6-pack-abs-6-days",   "tnimage": "http:\/\/example.com\/image.jpg",   "author": "john doe",   "tags": [     {       "name": "6 pack abs tips"     },     {       "name": "exercise tips"     },     {       "name": "workout videos"     }   ],   "category": {     "name": "fitness"   },   "datepublished": "2017-04-01",   "datecreated": "2015-01-20",   "datemodified": "2017-04-01",   "description": "seo keyword stuffed description fake tips abs here",   "articlebody": "full post body containing fake tips 6 packs. html" } 

of these tags, may exist, , may not. ones don't exist need created. , tags need created, urlslug generated using helper method.

the category, if filled, should inserted if doesn't exist.

the question

given scenario, how had post request against /api/posts endpoint, , ensure related tag , category entities added if don't exist?

if sample post shown above posted endpoint, how handle adding tags don't exist, category if doesn't exist, , adding new post?

also, approaching wrong in terms of rest design? if yes, recommended approach ensure data isn't inconsistent, i.e. tags added error occurs, there orphans now.

public class postscontroller : apicontroller {      [route("api/posts")]     [httppost]     public ihttpactionresult post([frombody]postdto post)     {         try         {             if (post == null)             {                 return badrequest();             }              // goes in here, add tags don't exist,              // category if doesn't exist             // , create post. add methods call repo methods             //              // there other way, i.e. approaching wrong?         }         catch (exception)         {             return internalservererror();         }     } 

a sample solution can here:

using (var context = new yourcontext())             {                 //find or create category                 category category = null;                 if (context.categories.any(cat => cat.name == post.category.name))                 {                     category = context.categories.firstordefault(cat => cat.name == post.category.name);                 }                 else                 {                     category = new category                     {                         name = post.category.name                     };                     context.categories.add(category);                 }                  //find or create tags                 var tags = new list<tag>();                 foreach (var tag in post.tags)                 {                     tag targetedtag;                     if (context.tags.any(t => t.name == tag.name))                     {                         targetedtag = context.tags.firstordefault(t => t.name == tag.name);                     }                     else                     {                         targetedtag = new tag                         {                             name = tag.name,                             // urlslug = use helper you've said                          };                         context.tags.add(targetedtag);                     }                     tags.add(targetedtag);                 }                  var targetedpost = new post                 {                     category = category,                     tags = tags,                     articlebody = post.articlebody,                     author = post.author,                     datecreated = post.datecreated,                     datemodified = post.datemodified,                     datepublished = post.datepublished,                     description = post.description,                     title = post.title,                     tnimage = post.tnimage,                     urlslug = post.urlslug                 };                  context.posts.add(targetedpost);                  context.savechanges();              } 

Comments